diff --git a/.github/actions/build-container/action.yml b/.github/actions/build-container/action.yml index bb6087159..ee7c2c125 100644 --- a/.github/actions/build-container/action.yml +++ b/.github/actions/build-container/action.yml @@ -10,7 +10,7 @@ inputs: runs: using: "composite" steps: - - uses: docker/metadata-action@v6.0.0 + - uses: docker/metadata-action@v6.2.0 id: metadata with: images: ghcr.io/${{ github.repository_owner }}/${{ inputs.container-name }} @@ -19,7 +19,7 @@ runs: type=ref,event=tag # set latest tag for default branch type=raw,value=main,enable={{is_default_branch}} - - uses: docker/build-push-action@v7.1.0 + - uses: docker/build-push-action@v7.3.0 id: push with: cache-from: type=gha @@ -32,7 +32,7 @@ runs: labels: ${{ steps.metadata.outputs.labels }} - name: Attest to REF image if: ${{ ! github.event.pull_request.head.repo.fork }} - uses: actions/attest@v4.1.0 + uses: actions/attest@v4.2.2 with: subject-name: ghcr.io/${{ github.repository_owner }}/${{ inputs.container-name }} subject-digest: ${{ steps.push.outputs.digest }} diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index ac1edaed4..7f7933e11 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -33,7 +33,7 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v10.0.1 with: - version: "0.11.6" + version: "0.12.7" python-version: "3.12" - name: Verify installable # TODO: this step fails we fix https://github.com/Climate-REF/climate-ref/issues/217 diff --git a/.github/workflows/regression-diff-report.yaml b/.github/workflows/regression-diff-report.yaml new file mode 100644 index 000000000..84fbc330c --- /dev/null +++ b/.github/workflows/regression-diff-report.yaml @@ -0,0 +1,95 @@ +# Build and host the HTML diff of the regression baselines changed on a branch. +# +# Called by the mint workflow after it pushes regenerated manifests, and dispatched by hand +# after a manual mint. Reads native blobs from the public store and writes only to the +# reports bucket, so it needs the reports token and nothing else. +name: Regression baselines (diff report) + +on: + workflow_call: + inputs: + base: + description: "Branch to diff against" + type: string + default: "main" + workflow_dispatch: + inputs: + base: + description: "Branch to diff against" + required: false + default: "main" + +permissions: + contents: read + pull-requests: write + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + report: + if: github.repository == 'Climate-REF/climate-ref' + runs-on: ubuntu-latest + environment: baseline-reports + defaults: + run: + shell: bash + steps: + - name: Check out the branch head + uses: actions/checkout@v7 + with: + # A called workflow sees the dispatching commit, not the one the mint job pushed. + ref: ${{ github.ref_name }} + fetch-depth: 0 + - name: Fetch the base branch + env: + BASE: ${{ inputs.base }} + run: git fetch --no-tags origin "+refs/heads/${BASE}:refs/remotes/origin/${BASE}" + - uses: ./.github/actions/setup + with: + python-version: "3.13" + - name: Find the pull request + id: pr + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + pr="$(gh pr list --head "${GITHUB_REF_NAME}" --state open --json number --jq '.[0].number')" + sha="$(git rev-parse --short=12 HEAD)" + if [ -n "${pr}" ]; then + echo "prefix=${pr}/${sha}" >> "${GITHUB_OUTPUT}" + else + echo "No open pull request for ${GITHUB_REF_NAME}. Uploading under branch/ and skipping the comment." + echo "prefix=branch/${GITHUB_REF_NAME}/${sha}" >> "${GITHUB_OUTPUT}" + fi + echo "number=${pr}" >> "${GITHUB_OUTPUT}" + - name: Build and upload the report + env: + REF_REPORT_STORE_ACCESS_KEY_ID: ${{ secrets.R2_REPORTS_ACCESS_KEY_ID }} + REF_REPORT_STORE_SECRET_ACCESS_KEY: ${{ secrets.R2_REPORTS_SECRET_ACCESS_KEY }} + BASE: ${{ inputs.base }} + PREFIX: ${{ steps.pr.outputs.prefix }} + run: | + uv run ref test-cases diff \ + --base "origin/${BASE}" \ + --html-dir report \ + --upload "${PREFIX}" \ + --comment-output comment.md + cat comment.md >> "${GITHUB_STEP_SUMMARY}" + - name: Post or update the sticky comment + # One comment per pull request: the marker identifies the one to edit on a later run. + if: steps.pr.outputs.number != '' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR: ${{ steps.pr.outputs.number }} + run: | + marker='' + existing="$(gh api "repos/${GITHUB_REPOSITORY}/issues/${PR}/comments" --paginate \ + --jq "map(select(.body | contains(\"${marker}\"))) | .[0].id // empty")" + if [ -n "${existing}" ]; then + gh api --method PATCH "repos/${GITHUB_REPOSITORY}/issues/comments/${existing}" \ + -F body=@comment.md + else + gh api --method POST "repos/${GITHUB_REPOSITORY}/issues/${PR}/comments" \ + -F body=@comment.md + fi diff --git a/.github/workflows/regression-mint.yaml b/.github/workflows/regression-mint.yaml index dd245ba1b..725e272fe 100644 --- a/.github/workflows/regression-mint.yaml +++ b/.github/workflows/regression-mint.yaml @@ -36,7 +36,7 @@ on: default: false # `contents` to commit the regenerated manifest/bundle back to the dispatched branch, -# `pull-requests` to post the baseline diff on the branch's open pull request. +# `pull-requests` so the called diff-report workflow can post on the branch's open pull request. permissions: contents: write pull-requests: write @@ -70,7 +70,7 @@ jobs: - name: Check out repository uses: actions/checkout@v7 with: - # Full history so the baseline diff can find the merge-base with the default branch. + # Full history so the mint can resolve the committed baselines against the default branch. fetch-depth: 0 - uses: ./.github/actions/setup with: @@ -114,13 +114,6 @@ jobs: if [ "${BUMP_VERSION}" = "true" ]; then args+=(--bump-version); fi if [ "${DRY_RUN}" = "true" ]; then args+=(--dry-run); fi uv run ref test-cases mint "${args[@]}" - - name: Fetch the default branch for the baseline diff - if: ${{ !inputs.dry_run }} - env: - DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} - run: | - git fetch --no-tags origin \ - "+refs/heads/${DEFAULT_BRANCH}:refs/remotes/origin/${DEFAULT_BRANCH}" - name: Commit regenerated baselines if: ${{ !inputs.dry_run }} env: @@ -160,37 +153,10 @@ jobs: done echo "::error::failed to push regenerated baselines after retries" exit 1 - - name: Report the baseline diff - # Runs after the commit so HEAD carries the regenerated manifests. - # Reporting only, so a failure here must not fail an otherwise successful mint. - if: ${{ !inputs.dry_run }} - continue-on-error: true - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} - run: | - # Two reports: the full one is small enough to keep as an artefact whatever the mint's - # size, while the capped one fits the comment and job-summary limits. - uv run python scripts/ci/mint_diff.py \ - --base "origin/${DEFAULT_BRANCH}" \ - --output mint-diff.md \ - --comment-output mint-diff-comment.md - # The job summary always gets a report, whether or not a pull request exists. - cat mint-diff-comment.md >> "${GITHUB_STEP_SUMMARY}" - - pr="$(gh pr list --head "${GITHUB_REF_NAME}" --state open --json number --jq '.[0].number')" - if [ -z "${pr}" ]; then - echo "No open pull request for ${GITHUB_REF_NAME}; the report is in the job summary only." - exit 0 - fi - gh pr comment "${pr}" --body-file mint-diff-comment.md - - name: Upload the full baseline diff - # The comment is capped at GitHub's 65 KB limit, so keep the untruncated report too. - if: ${{ !inputs.dry_run }} - continue-on-error: true - uses: actions/upload-artifact@v7 - with: - name: mint-diff - path: mint-diff.md - if-no-files-found: ignore + report: + needs: mint + if: ${{ !inputs.dry_run }} + uses: ./.github/workflows/regression-diff-report.yaml + with: + base: ${{ github.event.repository.default_branch }} diff --git a/Makefile b/Makefile index c25ad2363..d368db040 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,9 @@ # compatible so we're not too worried TEMP_FILE := $(shell mktemp) +# Workers used by the parallel test run. +PYTEST_WORKERS ?= 4 + # A helper script to get short descriptions of each target in the Makefile define PRINT_HELP_PYSCRIPT import re, sys @@ -164,7 +167,7 @@ test-quick: clean ## run all the tests at once # A new resource_intensive test has to live under a path listed here. uv run \ pytest tests packages \ - -r a -v --cov-report=term -n auto \ + -r a -v --cov-report=term -n $(PYTEST_WORKERS) \ -m "not resource_intensive" uv run \ pytest packages/climate-ref-core/tests/integration packages/climate-ref/tests/integration \ diff --git a/changelog/877.trivial.md b/changelog/877.trivial.md new file mode 100644 index 000000000..34de019b4 --- /dev/null +++ b/changelog/877.trivial.md @@ -0,0 +1,2 @@ +Updated the development type checker to mypy 2. +The declared requirement now matches the lockfile, so a fresh resolve cannot pick a mypy 1 release that disagrees with CI. diff --git a/changelog/897.fix.md b/changelog/897.fix.md new file mode 100644 index 000000000..e722aa81b --- /dev/null +++ b/changelog/897.fix.md @@ -0,0 +1,2 @@ +Dataset discovery now walks the whole directory tree instead of stopping 10 directories below the root. +The CMIP7 DRS nests files deeper than that, so ingesting a `MIP-DRS7` root found no files at all. diff --git a/changelog/898.feature.md b/changelog/898.feature.md new file mode 100644 index 000000000..a5fcef16a --- /dev/null +++ b/changelog/898.feature.md @@ -0,0 +1,17 @@ +Ingests the obs4REF collection under its own `obs4ref` source type. +The `instance_id` for `obs4ref` datasets now starts with `obs4REF`. +The diagnostics keep asking for obs4MIPs data. +Where a dataset is ingested from both, the newest version is used, and the obs4MIPs copy wins a tie. +Publishing a dataset to obs4MIPs therefore takes over from the registry copy without any change to the REF. +A newer registry version is still preferred over a stale published one, so nothing reruns for no reason. + +`ref doctor` gains three checks: `misfiled-obs4ref`, `superseded-obs4ref` and `unsolvable-diagnostics`. +Data ingested with `--source-type obs4mips` in earlier releases still solves, +but re-ingesting it with `--source-type obs4ref` is recommended. + +A data requirement can now declare the collections that may supply it, +through the new `fallback_source_types` field on `DataRequirement`. +A dataset present under `source_type` still wins, +and the data is delivered under `source_type` whichever collection it came from. +The solver, `ref doctor` and the generated reference data documentation all read the declaration. +No provider declares a fallback yet, so nothing changes behaviourally. diff --git a/changelog/899.fix.md b/changelog/899.fix.md new file mode 100644 index 000000000..439136af2 --- /dev/null +++ b/changelog/899.fix.md @@ -0,0 +1 @@ +Updated the sea ice sensitivity diagnostic for the recipe changes in ESMValTool v2.15. diff --git a/changelog/908.fix.md b/changelog/908.fix.md new file mode 100644 index 000000000..ca5d8fe8a --- /dev/null +++ b/changelog/908.fix.md @@ -0,0 +1,3 @@ +Removed the `immutable` flag from read-only SQLite connections. +The flag told SQLite to skip locking, which did not hold when a background run was writing +to the same database. The connection is still opened read-only. diff --git a/changelog/910.feature.md b/changelog/910.feature.md new file mode 100644 index 000000000..52e0ddb75 --- /dev/null +++ b/changelog/910.feature.md @@ -0,0 +1,6 @@ +`ref test-cases diff` renders the regression baselines changed on a branch as a local HTML report. +Images appear old and new side by side, with a button that overlays them. +Text outputs get a coloured diff, +and NetCDF and other binaries are listed with a size delta and a link to each blob. +`--html-dir` chooses where the report is written, +and `--no-fetch` skips blob downloads and reports sizes only. diff --git a/changelog/911.fix.md b/changelog/911.fix.md new file mode 100644 index 000000000..c318c36bd --- /dev/null +++ b/changelog/911.fix.md @@ -0,0 +1,2 @@ +PMP executions are now capped at two threads each. +Without a limit the scientific stack sized its thread pools from the machine's core count. diff --git a/changelog/912.feature.md b/changelog/912.feature.md new file mode 100644 index 000000000..ed9f4c456 --- /dev/null +++ b/changelog/912.feature.md @@ -0,0 +1,4 @@ +`ref test-cases diff --upload ` publishes the report to a public object store, +and `--comment-output ` writes the pull request comment markdown that links into it. + +Reports are stored in their own bucket, separate from the baselines. diff --git a/changelog/913.feature.md b/changelog/913.feature.md new file mode 100644 index 000000000..26ba72784 --- /dev/null +++ b/changelog/913.feature.md @@ -0,0 +1,4 @@ +Summarise the changes to `.nc` files in the `ref test-cases diff` report. +Each file gets a collapsible listing of its ncdump-style header and a table with one row per +data variable carrying min, max, mean, NaN count, the largest absolute and relative difference, +and the number of cells that differ. diff --git a/changelog/915.feature.md b/changelog/915.feature.md new file mode 100644 index 000000000..daf11ead5 --- /dev/null +++ b/changelog/915.feature.md @@ -0,0 +1 @@ +Regression baseline diffs are now published as an HTML report linked from a short pull request comment, with images shown side by side and NetCDF outputs summarised per variable. diff --git a/docs/api-surface.md b/docs/api-surface.md index 53d1d86da..90fcafe66 100644 --- a/docs/api-surface.md +++ b/docs/api-surface.md @@ -34,6 +34,7 @@ The primary module providers interact with. - Override `Diagnostic.build_execution_result(definition) -> ExecutionResult` - Set `Diagnostic.data_requirements`, `facets`, `slug`, `name` - Set `Diagnostic.test_data_spec` for test case support +- Set `DataRequirement.fallback_source_types` to name the collections that may supply a requirement --- diff --git a/docs/background/architecture.md b/docs/background/architecture.md index 4e220bb90..bd51ca135 100644 --- a/docs/background/architecture.md +++ b/docs/background/architecture.md @@ -365,7 +365,7 @@ Key characteristics: - The backend is a **read-only consumer** of the REF database. It opens the database without running migrations - (SQLite can be opened immutable so the state volume can be mounted read-only) + (SQLite is opened with `mode=ro`, so the state volume can be mounted read-only) and reports the results the compute engine has already produced. - It depends on the `climate-ref` library directly for configuration, models and the provider registry. The database schema remains owned by `climate-ref` migrations. diff --git a/docs/background/regression-baselines.md b/docs/background/regression-baselines.md index 7b3c742da..f85b4ea2a 100644 --- a/docs/background/regression-baselines.md +++ b/docs/background/regression-baselines.md @@ -250,7 +250,7 @@ the `--json` output drives CI's dispatch of the `replay` jobs. ## Continuous integration -The lifecycle commands are wired into three GitHub Action workflows. +The lifecycle commands are wired into four GitHub Action workflows. The minting process requires credentials to upload data. Since this is a public project we have to be careful about when this is run to not leak these credentials. @@ -258,6 +258,7 @@ Since this is a public project we have to be careful about when this is run to n | --- | --- | --- | --- | | `regression-pr-gate.yaml` | every pull request | none | Runs the coupling gate, then `replay`s every case it routes to `replay`. | | `regression-mint.yaml` | manual dispatch | R2 write | `mint`s native baselines and commits the regenerated manifest back to the branch. | +| `regression-diff-report.yaml` | called by the mint + manual | R2 write (reports bucket) | Builds the HTML diff of the changed baselines and links it from a sticky pull-request comment. | | `regression-drift.yaml` | nightly + manual | none | `replay`s every baseline to catch silent drift. | ### PR gate (`regression-pr-gate.yaml`) @@ -301,6 +302,7 @@ Dispatch it on the feature branch that should receive the new baseline: the job runs `mint`, and commits the regenerated `manifest.json` (and committed bundle) back to that branch, so the change is reviewed through its pull request and no developer ever needs write credentials. A `dry_run` input previews without uploading or committing, and the job refuses to run on the default branch. +Once the commit is pushed, the mint calls `regression-diff-report.yaml` to publish the diff of what it changed. !!! warning "The mint commit does not re-trigger the PR gate" The mint job pushes with the default `GITHUB_TOKEN`, and GitHub deliberately does not start new workflow runs for such pushes. @@ -317,6 +319,47 @@ A `dry_run` input previews without uploading or committing, and the job refuses The endpoint and bucket default to the production R2 account (`REF_NATIVE_STORE_S3_ENDPOINT_URL` / `REF_NATIVE_STORE_BUCKET` override them). +### Diff report (`regression-diff-report.yaml`) + +Reviewing a minted baseline means looking at what actually moved, which a JSON manifest does not show. +So this workflow builds an HTML report of every test case whose baseline changed against the base branch: + +- Images are shown two-up, the old beside the new. +- Text outputs get a coloured line diff. +- A changed NetCDF gets a header diff plus one row of statistics per variable, shaded only where the values moved. + +The report is uploaded to the public reports bucket and served at +`https://reports.baselines.climate-ref.org///index.html`. +The workflow then posts a short comment on the branch's open pull request linking to it. +The comment carries a hidden marker, so a later run edits that same comment rather than stacking a new one. +A run on a branch with no open pull request uploads under `branch///` and writes the summary to the job log only. + +The mint workflow calls this automatically. +After minting on a workstation and pushing the result by hand, dispatch it yourself: + +```bash +gh workflow run regression-diff-report.yaml --ref +``` + +The same report can be built locally, without any credentials: + +```bash +uv run ref test-cases diff --base origin/main --html-dir out/ +``` + +!!! note "Required repository configuration" + Create a `baseline-reports` Environment (Settings -> Environments) with **no required reviewers**, + so a mint run does not stop for a second approval, and add two secrets to it + holding an R2 token scoped to the `ref-baselines-reports` bucket: + + - `R2_REPORTS_ACCESS_KEY_ID` -> `REF_REPORT_STORE_ACCESS_KEY_ID` + - `R2_REPORTS_SECRET_ACCESS_KEY` -> `REF_REPORT_STORE_SECRET_ACCESS_KEY` + + The reports live in their own bucket because an R2 token cannot be scoped write-only or to a prefix. + A token that could write reports into the baselines bucket could also overwrite a baseline. + The endpoint, bucket and public URL default to the production R2 account + (`REF_REPORT_STORE_S3_ENDPOINT_URL` / `REF_REPORT_STORE_BUCKET` / `REF_REPORT_STORE_URL` override them). + ### Nightly drift (`regression-drift.yaml`) A scheduled (and manually dispatchable) job `replay`s every referenced native blob against the committed bundle. diff --git a/docs/development.md b/docs/development.md index a29448fc9..cf5735f88 100644 --- a/docs/development.md +++ b/docs/development.md @@ -62,7 +62,7 @@ For development, we use a consistent set of decimated sample data. ```bash make fetch-test-data uv run ref datasets ingest --source-type cmip6 $PWD/tests/test-data/sample-data/CMIP6/ -uv run ref datasets ingest --source-type obs4mips $PWD/tests/test-data/sample-data/obs4REF/ +uv run ref datasets ingest --source-type obs4ref $PWD/tests/test-data/sample-data/obs4REF/ ``` This is enough to run a `solve` against. diff --git a/docs/getting-started/02-download-datasets.md b/docs/getting-started/02-download-datasets.md index 19945ecec..c65a3ab10 100644 --- a/docs/getting-started/02-download-datasets.md +++ b/docs/getting-started/02-download-datasets.md @@ -102,25 +102,22 @@ but it also re-fetches four datasets the obs4REF registry already provides, so only use it if you are **not** using that registry — see the warning below. Files land in the [intake-esgf `local_cache`](https://intake-esgf.readthedocs.io/en/latest/configure.html), -and are ingested with the `obs4mips` source type, the same as the obs4REF collection. +and are ingested with the `obs4mips` source type. -/// admonition | Do not fetch these twice - type: warning +The obs4REF collection is ingested with the `obs4ref` source type instead. + +/// admonition | Fetching these twice + type: note The script also fetches `CERES-EBAF-4-2`, `GPCP-Monthly-3-2`, `HadISST-1-1` and `TropFlux-1-0`. These are the ESGF-published copies of datasets that were curated for the REF before publication, so the obs4REF registry ships them as well. -**If you have already fetched the obs4REF registry, do not fetch these from ESGF as well.** -Where the two copies carry the same version they share an `instance_id` and ingest as a single -dataset holding *both* sets of files, which covers the record twice. -`GPCP-Monthly-3-2` `pr` `v20231205` is the clearest case: obs4REF ships one file spanning 1983-2023 and ESGF ships 41 yearly files spanning the same period, giving one dataset of 42 files. -A diagnostic reading it sees every time step twice. - -Where the published copy carries a *newer* version, there is no such problem: -the two ingest as separate datasets and the catalog uses the later version. - -This is temporary until we split the obs4REF ingest from the obs4MIPs ingest. +If you fetch the same dataset from ESGF/obs4MIPs as well as from the obs4REF registry, +the newest version is used. +The ESGF copy wins when the versions are the same. +obs4MIPs is the preferred home of the reference data. +The registry only fills in what is not published yet. /// ### Future work diff --git a/docs/getting-started/03-ingest.md b/docs/getting-started/03-ingest.md index 74520a90e..6554b9d67 100644 --- a/docs/getting-started/03-ingest.md +++ b/docs/getting-started/03-ingest.md @@ -10,14 +10,29 @@ Before you begin, ensure you have: ## 1. Ingest reference datasets -The `obs4REF` collection we downloaded in the previous step uses the `obs4mips` source type as the data are obs4MIPs compatible. This command will extract metadata from the files and store it in the Climate-REF catalog, and print a summary of the ingested datasets. +The `obs4REF` collection we downloaded in the previous step is ingested under the `obs4ref` source type. +The files follow the obs4MIPs conventions, but are not yet published on ESGF. + +Where a dataset is ingested from both, the newest version is used. +The obs4MIPs copy wins when the versions are the same. +This command extracts metadata from the files and stores it in the Climate-REF catalog. +It then prints a summary of the ingested datasets. ```bash -ref datasets ingest --source-type obs4mips $REF_CONFIGURATION/datasets/obs4ref +ref datasets ingest --source-type obs4ref $REF_CONFIGURATION/datasets/obs4ref ``` Replace `$REF_CONFIGURATION/datasets/obs4ref` with the directory used when [fetched the obs4REF data](02-download-datasets.md#fetch-obs4ref-datasets). +/// admonition | Upgrading from an earlier release + type: note + +Earlier releases ingested this collection with `--source-type obs4mips`. +Those datasets still solve, but the catalog cannot tell them apart from published obs4MIPs data. +Re-ingest the collection with `--source-type obs4ref`, then retract the old rows. +`ref doctor` lists them under `misfiled-obs4ref`. +/// + ## 2. Ingest CMIP6 data To ingest CMIP6 files, point the CLI at a directory of netCDF files and set `cmip6` as the source type: diff --git a/docs/getting-started/quickstart.md b/docs/getting-started/quickstart.md index b4b37da29..c30a529ac 100644 --- a/docs/getting-started/quickstart.md +++ b/docs/getting-started/quickstart.md @@ -105,11 +105,12 @@ ref datasets fetch-data --registry quickstart --output-directory $REF_CONFIGURAT ## 4. Ingest (~20 s) Extract metadata from the downloaded files into the local catalog. -The model data is CMIP6; the observation uses the `obs4mips` source type: +The model data is CMIP6. +The observation comes from the obs4REF registry, so it is ingested under the `obs4ref` source type. ```bash ref datasets ingest --source-type cmip6 $REF_CONFIGURATION/datasets/sample-data/CMIP6 -ref datasets ingest --source-type obs4mips $REF_CONFIGURATION/datasets/quickstart/obs4REF +ref datasets ingest --source-type obs4ref $REF_CONFIGURATION/datasets/quickstart/obs4REF ``` Check the catalog: diff --git a/docs/how-to-guides/diagnose-a-deployment.md b/docs/how-to-guides/diagnose-a-deployment.md index 0c25bfd9a..928025faa 100644 --- a/docs/how-to-guides/diagnose-a-deployment.md +++ b/docs/how-to-guides/diagnose-a-deployment.md @@ -1,9 +1,14 @@ # Diagnose a deployment -`ref doctor` looks for the problems that a solve hides rather than reports: reference data that is missing, -so its diagnostics quietly plan no executions; -data ingested under a source type no diagnostic requires, so nothing selects it; -and datasets whose files cover the same period twice, so a diagnostic reads that period more than once. +`ref doctor` looks for the problems that a solve hides rather than reports. + +- Reference data is missing, so its diagnostics quietly plan no executions. +- Data is ingested under a source type no diagnostic requires, so nothing selects it. +- obs4REF data is ingested as `obs4mips`, so the catalog cannot say where it came from. +- An obs4REF dataset has since been published to obs4MIPs, so the registry copy is no longer used. +- A dataset's files cover the same period twice, so a diagnostic reads that period more than once. +- A diagnostic cannot be solved at all by the ingested data. + The finding names the requirement that goes unmet. ```bash ref doctor @@ -14,7 +19,7 @@ under the remedy they have in common, so a deployment missing twenty reference datasets reads as one instruction and twenty names: ```text -3 findings from 4 checks: 3 warnings +3 findings from 7 checks: 3 warnings missing-reference-data 3 warnings Fetch these, then ingest the directory they land in. diff --git a/docs/how-to-guides/docker_deployment.md b/docs/how-to-guides/docker_deployment.md index 239c7b85f..4fae42ef5 100644 --- a/docs/how-to-guides/docker_deployment.md +++ b/docs/how-to-guides/docker_deployment.md @@ -43,7 +43,7 @@ These data can be ingested into the REF using the following commands (note that ```bash docker-compose run --rm climate-ref datasets ingest --source-type cmip6 /ref/data/CMIP6 -docker-compose run --rm climate-ref datasets ingest --source-type obs4mips /ref/data/obs4ref +docker-compose run --rm climate-ref datasets ingest --source-type obs4ref /ref/data/obs4ref ``` After the data has been ingested, the REF can be run using the following command. diff --git a/docs/how-to-guides/reading-results-locally.md b/docs/how-to-guides/reading-results-locally.md index a787badb0..dbc0489d1 100644 --- a/docs/how-to-guides/reading-results-locally.md +++ b/docs/how-to-guides/reading-results-locally.md @@ -38,7 +38,7 @@ with Database.from_config(config, read_only=True) as db: # `df` is a plain DataFrame and remains valid out here, after the session has closed. ``` -`read_only=True` opens SQLite in immutable read-only mode and skips migrations, +`read_only=True` opens SQLite in read-only mode and skips migrations, so the read layer never mutates the database you point it at. `Reader` is a thin entry point. diff --git a/packages/climate-ref-core/src/climate_ref_core/diagnostics.py b/packages/climate-ref-core/src/climate_ref_core/diagnostics.py index 5aaf4018f..cd5825e4f 100644 --- a/packages/climate-ref-core/src/climate_ref_core/diagnostics.py +++ b/packages/climate-ref-core/src/climate_ref_core/diagnostics.py @@ -443,6 +443,14 @@ class DataRequirement: This is effectively an AND operation. """ + fallback_source_types: tuple[SourceDatasetType, ...] = field(factory=tuple) + """ + Source types that may supply this requirement when ``source_type`` does not hold the dataset. + + A dataset present under ``source_type`` always wins, + and the data is delivered under ``source_type`` whichever collection it came from. + """ + def apply_filters(self, data_catalog: pd.DataFrame) -> pd.DataFrame: """ Apply filters to a DataFrame-based data catalog. diff --git a/packages/climate-ref-core/src/climate_ref_core/reference_data.py b/packages/climate-ref-core/src/climate_ref_core/reference_data.py index 57dec4c34..ee4970182 100644 --- a/packages/climate-ref-core/src/climate_ref_core/reference_data.py +++ b/packages/climate-ref-core/src/climate_ref_core/reference_data.py @@ -141,8 +141,8 @@ def source_ids_by_registry( parser = _registry_key_parser(entry.source_type) if parser is None: continue - # obs4REF data is ingested under the obs4MIPs source type, so a registry declaring - # obs4REF supplies requirements written against either. + # The obs4REF registry carries what obs4MIPs has not published yet, + # so it supplies requirements written against either. source_types = {entry.source_type.value} if entry.source_type is SourceDatasetType.obs4REF: source_types.add(SourceDatasetType.obs4MIPs.value) @@ -182,6 +182,8 @@ def collect_required_reference_data( variables: dict[tuple[str, str], set[str]] = defaultdict(set) diagnostics: dict[tuple[str, str], set[DiagnosticReference]] = defaultdict(set) + # Source types a requirement may be met from, its own first + suppliers: dict[tuple[str, str], list[str]] = defaultdict(list) for provider in providers: for diagnostic in summarize_provider(provider).diagnostics: @@ -198,11 +200,20 @@ def collect_required_reference_data( key = (requirement.source_type, source_id) variables[key].update(requirement.variables) diagnostics[key].add(reference) + for source_type in (requirement.source_type, *requirement.fallback_source_types): + if source_type not in suppliers[key]: + suppliers[key].append(source_type) datasets = [] for (source_type, source_id), variable_ids in variables.items(): - registry_names = registry_of.get((source_type, source_id), []) - registry_name = registry_names[0] if registry_names else None + registry_name = next( + ( + registry_of[(supplier, source_id)][0] + for supplier in suppliers[(source_type, source_id)] + if registry_of.get((supplier, source_id)) + ), + None, + ) datasets.append( ReferenceDataset( source_type=source_type, diff --git a/packages/climate-ref-core/src/climate_ref_core/regression/__init__.py b/packages/climate-ref-core/src/climate_ref_core/regression/__init__.py index 21c73d877..863b963c1 100644 --- a/packages/climate-ref-core/src/climate_ref_core/regression/__init__.py +++ b/packages/climate-ref-core/src/climate_ref_core/regression/__init__.py @@ -37,6 +37,10 @@ sha256_file, verify_committed_integrity, ) +from climate_ref_core.regression.report_store import ( + ReportStore, + build_report_store, +) from climate_ref_core.regression.store import ( NativeStore, NativeStoreUnavailableError, @@ -53,11 +57,13 @@ "NativeEntry", "NativeStore", "NativeStoreUnavailableError", + "ReportStore", "S3WriteConfig", "Tolerance", "assert_bundle_regression", "build_native_snapshot", "build_native_store", + "build_report_store", "compare_json_content", "compute_committed_digests", "decide_coupling", diff --git a/packages/climate-ref-core/src/climate_ref_core/regression/report_store.py b/packages/climate-ref-core/src/climate_ref_core/regression/report_store.py new file mode 100644 index 000000000..3ccec9450 --- /dev/null +++ b/packages/climate-ref-core/src/climate_ref_core/regression/report_store.py @@ -0,0 +1,223 @@ +""" +Named-key store for hosted baseline diff reports. + +A diff report is a small static site, so its objects are addressed by path rather than by digest. +That is the one thing it does not share with :class:`~climate_ref_core.regression.store.NativeStore`, +which is content-addressed and must stay that way. +Everything below the key (where the store lives, how it authenticates, preflight, putting a file) +is the shared transport in :mod:`~climate_ref_core.regression.store`. + +Reports live in their own public bucket, served at ``{url}/{key}``. + +Write credentials are resolved from the following in order: + +- ``REF_REPORT_STORE_ACCESS_KEY_ID`` / ``REF_REPORT_STORE_SECRET_ACCESS_KEY``, +- ``REF_REPORT_STORE_PROFILE``, +- boto3's default chain +""" + +import re +import shutil +from pathlib import Path + +from attrs import field, frozen +from loguru import logger + +from climate_ref_core.paths import safe_path + +from .store import ( + S3WriteConfig, + _local_root, + _preflight_store, + _StoreConfigProtocol, + _write_config_from_env, +) + +_KEY_PATTERN = re.compile(r"[A-Za-z0-9._/-]+") + + +def _validate_key(key: str, base: Path | None = None) -> Path: + """ + Check a report key is a safe relative path and return the path it names. + + The character class is the object-key rule, narrower than a filesystem path because the key + also has to survive a URL. Containment is left to :func:`safe_path`, which is what the rest + of the regression package validates paths with. + + Parameters + ---------- + key + The key to check, for example ``912/0c7e1d4abc12/index.html``. + base + The local store root the key is joined onto, or ``None`` for a remote store, + where there is no directory to escape. + + Returns + ------- + : + ``base / key`` when a base is given, otherwise the key as a relative path. + + Raises + ------ + ValueError + If the key uses characters outside ``[A-Za-z0-9._/-]``, is empty, absolute, or + contains a ``..`` segment, or if it escapes ``base``. + """ + if not _KEY_PATTERN.fullmatch(key): + raise ValueError( + f"Unsafe report store key {key!r}: may only contain letters, digits, dot, " + "underscore, hyphen and forward slash." + ) + return safe_path(key, base, label="report store key") + + +@frozen +class ReportStore: + """ + Named-key store for hosted baseline diff reports. + + A local store (a ``file://`` URL or a bare path) writes under its root and needs no credentials. + A remote store writes through an :class:`S3WriteConfig` and is served at ``{url}/{key}``. + + Parameters + ---------- + url + Where reports are served from: an ``http(s)://`` base URL, a ``file:///absolute/path`` + URL, or a bare filesystem path. + write + The S3 endpoint, bucket and credentials a remote store writes with. + ``None`` leaves a remote store read-only. + A local store ignores it and is always writable. + """ + + url: str + write: S3WriteConfig | None = None + root: Path | None = field(init=False) + """The local store root, or ``None`` when this store is remote.""" + + @root.default + def _resolve_root(self) -> Path | None: + """Resolve the local root once at construction, which also validates the URL.""" + return _local_root(self.url) + + def url_for(self, key: str) -> str: + """ + Return the public URL a key is served at. + + Parameters + ---------- + key + The key, relative and slash-separated. + + Returns + ------- + : + An ``http(s)://`` URL for a remote store, or a ``file://`` URL for a local one. + + Raises + ------ + ValueError + If the key is not a safe relative path. + """ + root = self.root + if root is not None: + return _validate_key(key, root).absolute().as_uri() + _validate_key(key) + return f"{self.url.rstrip('/')}/{key}" + + def put(self, key: str, path: Path, content_type: str) -> str: + """ + Store ``path`` under ``key``, overwriting whatever was there. + + Reports are rewritten whenever a pull request is re-minted, so a put always replaces. + + Parameters + ---------- + key + The key to store under, relative and slash-separated. + path + The local file to store. + content_type + The MIME type the object is served with. A browser will not render an + uploaded page without it, since R2 defaults to a binary type. + + Returns + ------- + : + The URL the key is served at. + + Raises + ------ + ValueError + If the key is not a safe relative path. + NotImplementedError + If this is an anonymous remote store, which cannot write. + """ + root = self.root + if root is not None: + dest = _validate_key(key, root) + dest.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(str(path), str(dest)) + else: + _validate_key(key) + write = self.write + if write is None: + raise NotImplementedError( + f"Report store {self.url} is a public-read store, so put() is not supported. " + "Upload against a local path or a credentialed remote store." + ) + write.client().upload_file(str(path), write.bucket, key, ExtraArgs={"ContentType": content_type}) + logger.debug(f"ReportStore.put: {path} -> {key}") + return self.url_for(key) + + def preflight(self) -> None: + """ + Verify the store is reachable and usable before uploading to it. + + Raises + ------ + NativeStoreUnavailableError + If the store cannot be reached or used, with an operator-facing message. + """ + _preflight_store(self.root, self.write, "Report store") + + +def build_report_store(config: _StoreConfigProtocol, *, writable: bool) -> ReportStore: + """ + Build a :class:`ReportStore` from a report-store config object. + + With ``writable=False`` the returned store is anonymous and credential-free. + With ``writable=True`` and a remote URL the S3 endpoint and bucket come from the config, + and authentication is read from the environment + (``REF_REPORT_STORE_ACCESS_KEY_ID`` / ``REF_REPORT_STORE_SECRET_ACCESS_KEY``, + else ``REF_REPORT_STORE_PROFILE``, else boto3's default chain), + so secrets never live in the persisted config. + A local store is always readable and writable, so ``writable`` makes no difference to it. + + Parameters + ---------- + config + A config object providing ``url``, ``s3_endpoint_url`` and ``bucket``. + Typically ``app_config.report_store``. + writable + Whether the store must be able to write. + + Returns + ------- + : + The configured store. + + Raises + ------ + ValueError + If the URL scheme is unrecognised, or a writable remote store is requested + without an S3 endpoint / bucket configured. + """ + store = ReportStore(url=config.url) + if not writable or store.root is not None: + # A local store is already writable, and a read-only store needs no credentials. + return store + return ReportStore( + url=config.url, + write=_write_config_from_env(config.s3_endpoint_url, config.bucket, "REF_REPORT_STORE"), + ) diff --git a/packages/climate-ref-core/src/climate_ref_core/regression/store.py b/packages/climate-ref-core/src/climate_ref_core/regression/store.py index 784f7e325..c50030e4c 100644 --- a/packages/climate-ref-core/src/climate_ref_core/regression/store.py +++ b/packages/climate-ref-core/src/climate_ref_core/regression/store.py @@ -213,6 +213,9 @@ class S3WriteConfig: profile Named AWS/R2 profile to authenticate with, or ``""`` for the default session. Ignored when explicit ``access_key_id`` / ``secret_access_key`` are supplied. + env_prefix + Prefix of the environment variables this config was resolved from, for example + ``REF_REPORT_STORE``. Only used to name the right variable in an error message. """ endpoint_url: str @@ -220,17 +223,18 @@ class S3WriteConfig: access_key_id: str = field(default="", repr=False) secret_access_key: str = field(default="", repr=False) profile: str = "" + env_prefix: str = "REF_NATIVE_STORE" def __attrs_post_init__(self) -> None: """Fail fast at construction (mint startup) when the routing config is missing.""" if not self.endpoint_url: raise ValueError( - "R2 native store requires an S3 endpoint URL. Set REF_NATIVE_STORE_S3_ENDPOINT_URL " + f"R2 store requires an S3 endpoint URL. Set {self.env_prefix}_S3_ENDPOINT_URL " "(e.g. https://.eu.r2.cloudflarestorage.com)." ) if not self.bucket: raise ValueError( - "R2 native store requires a bucket name. Set REF_NATIVE_STORE_BUCKET (e.g. ref-baselines)." + f"R2 store requires a bucket name. Set {self.env_prefix}_BUCKET (e.g. ref-baselines)." ) def client(self) -> Any: @@ -238,6 +242,114 @@ def client(self) -> Any: return _s3_client(self.endpoint_url, self.access_key_id, self.secret_access_key, self.profile) +def _preflight_store(root: Path | None, write: S3WriteConfig | None, label: str) -> None: + """ + Verify a store is reachable and usable before relying on it. + + A local store's root is created if needed and checked for writability. + A writable remote store performs a cheap authenticated ``HEAD`` on a sentinel key, + which is expected to be absent: + a ``404`` means the request authenticated and the store is usable, + while ``401`` / ``403`` become actionable errors, + so a misconfigured credential is caught before the (slow) upload rather than after. + ``head_object`` is used rather than ``head_bucket``, + so the check works with least-privilege, object-scoped tokens. + + An anonymous remote store has nothing to verify up front, since it has no credentials. + + Parameters + ---------- + root + The local store root, or ``None`` when the store is remote. + write + How a remote store writes, or ``None`` when it is anonymous. + label + How the store is named in an error message, for example ``"Native store"``. + + Raises + ------ + NativeStoreUnavailableError + If the store cannot be reached or used, with an operator-facing message. + """ + if root is not None: + try: + root.mkdir(parents=True, exist_ok=True) + except OSError as exc: + raise NativeStoreUnavailableError( + f"Local {label.lower()} root {root} could not be created: {exc}" + ) from exc + if not os.access(root, os.W_OK): + raise NativeStoreUnavailableError(f"Local {label.lower()} root {root} is not writable.") + logger.debug(f"Local {label.lower()} ready at {root}") + return + if write is None: + return + + from botocore.exceptions import BotoCoreError, ClientError # noqa: PLC0415 - optional dependency + + creds = ( + f"Check {write.env_prefix}_PROFILE, or {write.env_prefix}_ACCESS_KEY_ID / " + f"{write.env_prefix}_SECRET_ACCESS_KEY." + ) + where = f"for bucket {write.bucket!r} at {write.endpoint_url}" + try: + write.client().head_object(Bucket=write.bucket, Key=_PREFLIGHT_PROBE_KEY) + except BotoCoreError as exc: + # Covers NoCredentialsError, where the whole chain resolved nothing, and DNS failures. + raise NativeStoreUnavailableError(f"{label} could not be reached {where}: {exc} {creds}") from exc + except ClientError as exc: + status = _http_status(exc) + if status == _HTTP_NOT_FOUND: + pass # authenticated, and the probe object is simply absent, so the store is usable + elif status in _AUTH_REJECTED_STATUSES: + raise NativeStoreUnavailableError( + f"{label} authentication failed (HTTP {status}) {where}: the credentials were " + f"rejected or malformed. {creds}" + ) from exc + elif status == _HTTP_FORBIDDEN: + raise NativeStoreUnavailableError( + f"{label} access denied (HTTP 403) {where}: the request was forbidden. The secret " + f"key may be wrong, or the token may lack object read and write on this bucket. " + f"Check the credentials and the token's permissions." + ) from exc + else: + raise NativeStoreUnavailableError( + f"{label} preflight failed (HTTP {status}) {where}: {exc}" + ) from exc + logger.info(f"{label} authenticated: bucket {write.bucket!r} at {write.endpoint_url}") + + +def _write_config_from_env(endpoint_url: str, bucket: str, env_prefix: str) -> S3WriteConfig: + """ + Build an :class:`S3WriteConfig` from non-secret routing plus credentials in the environment. + + Credentials are read here, at build time, so they never live in the persisted config. + + Parameters + ---------- + endpoint_url + S3 API endpoint for the bucket's account, without the bucket. + bucket + Name of the bucket to write to. + env_prefix + Prefix of the credential environment variables, for example ``REF_NATIVE_STORE``. + + Returns + ------- + : + The write config, with empty credentials where the environment supplies none, + which falls through to the named profile and then boto3's default chain. + """ + return S3WriteConfig( + endpoint_url=endpoint_url, + bucket=bucket, + access_key_id=os.environ.get(f"{env_prefix}_ACCESS_KEY_ID", ""), + secret_access_key=os.environ.get(f"{env_prefix}_SECRET_ACCESS_KEY", ""), + profile=os.environ.get(f"{env_prefix}_PROFILE", ""), + env_prefix=env_prefix, + ) + + @frozen class NativeStore: """ @@ -421,77 +533,20 @@ def preflight(self) -> None: """ Verify the store is reachable and usable before relying on it. - A local store's root is created if needed and checked for writability. - A writable remote store performs a cheap authenticated ``HEAD`` on a sentinel key, - which is expected to be absent: - a ``404`` means the request authenticated and the store is usable, - while ``401`` / ``403`` become actionable errors, - so a misconfigured credential is caught before the (slow) diagnostic run rather than after. - ``head_object`` is used rather than ``head_bucket``, - so the check works with least-privilege, object-scoped tokens. - - An anonymous remote store has nothing to verify up front. - It has no credentials, and every read is hash-checked per blob. - Raises ------ NativeStoreUnavailableError If the store cannot be reached or used, with an operator-facing message. """ - root = self.root - if root is not None: - try: - root.mkdir(parents=True, exist_ok=True) - except OSError as exc: - raise NativeStoreUnavailableError( - f"Local native store root {root} could not be created: {exc}" - ) from exc - if not os.access(root, os.W_OK): - raise NativeStoreUnavailableError(f"Local native store root {root} is not writable.") - logger.debug(f"Local native store ready at {root}") - return - write = self.write - if write is None: - return + _preflight_store(self.root, self.write, "Native store") - from botocore.exceptions import ClientError # noqa: PLC0415 - optional dependency - try: - write.client().head_object(Bucket=write.bucket, Key=_PREFLIGHT_PROBE_KEY) - except ClientError as exc: - status = _http_status(exc) - if status == _HTTP_NOT_FOUND: - pass # authenticated, and the probe object is simply absent, so the store is usable - elif status in _AUTH_REJECTED_STATUSES: - raise NativeStoreUnavailableError( - f"Native store authentication failed (HTTP {status}) for bucket {write.bucket!r} at " - f"{write.endpoint_url}: the credentials were rejected or malformed. Check " - f"REF_NATIVE_STORE_PROFILE, or REF_NATIVE_STORE_ACCESS_KEY_ID / " - f"REF_NATIVE_STORE_SECRET_ACCESS_KEY." - ) from exc - elif status == _HTTP_FORBIDDEN: - raise NativeStoreUnavailableError( - f"Native store access denied (HTTP 403) for bucket {write.bucket!r} at " - f"{write.endpoint_url}: the request was forbidden. The secret key may be wrong, " - f"or the token may lack object read and write on this bucket. Check the " - f"credentials and the token's permissions." - ) from exc - else: - raise NativeStoreUnavailableError( - f"Native store preflight failed (HTTP {status}) for bucket {write.bucket!r} at " - f"{write.endpoint_url}: {exc}" - ) from exc - logger.info(f"Native store authenticated: bucket {write.bucket!r} at {write.endpoint_url}") - - -class _NativeStoreConfigProtocol(Protocol): +class _StoreConfigProtocol(Protocol): """ - Structural protocol for the native-store config object expected by :func:`build_native_store`. - - Both :class:`climate_ref.config.NativeStoreConfig` and test doubles satisfy - this interface without an import dependency on the app package. + Structural protocol for the store config objects the factories accept. - This keeps ``climate_ref_core`` free of any import dependency on ``climate_ref``. + Both :mod:`climate_ref.config` classes and test doubles satisfy it without an import + dependency on the app package, which keeps ``climate_ref_core`` free of one. ``s3_endpoint_url`` and ``bucket`` are non-secret routing config consumed only by a writable remote store. Write credentials are intentionally **not** part of this protocol. @@ -501,9 +556,6 @@ class _NativeStoreConfigProtocol(Protocol): @property def url(self) -> str: ... - @property - def cache_dir(self) -> Path: ... - @property def s3_endpoint_url(self) -> str: ... @@ -511,14 +563,17 @@ def s3_endpoint_url(self) -> str: ... def bucket(self) -> str: ... +class _NativeStoreConfigProtocol(_StoreConfigProtocol, Protocol): + """The store config plus the cache directory an anonymous native read needs.""" + + @property + def cache_dir(self) -> Path: ... + + def build_native_store(config: _NativeStoreConfigProtocol, *, writable: bool) -> NativeStore: """ Build a :class:`NativeStore` from a native-store config object. - Accepts any object that exposes ``url``, ``cache_dir``, ``s3_endpoint_url`` and ``bucket`` - (satisfying :class:`_NativeStoreConfigProtocol`), so callers pass ``config.native_store`` - rather than the full :class:`~climate_ref.config.Config`. - With ``writable=False`` the returned store is anonymous and credential-free, which suits the CI read and replay paths. With ``writable=True`` and a remote URL the S3 endpoint and bucket come from the config, @@ -554,11 +609,5 @@ def build_native_store(config: _NativeStoreConfigProtocol, *, writable: bool) -> return NativeStore( url=config.url, cache_dir=config.cache_dir, - write=S3WriteConfig( - endpoint_url=config.s3_endpoint_url, - bucket=config.bucket, - access_key_id=os.environ.get("REF_NATIVE_STORE_ACCESS_KEY_ID", ""), - secret_access_key=os.environ.get("REF_NATIVE_STORE_SECRET_ACCESS_KEY", ""), - profile=os.environ.get("REF_NATIVE_STORE_PROFILE", ""), - ), + write=_write_config_from_env(config.s3_endpoint_url, config.bucket, "REF_NATIVE_STORE"), ) diff --git a/packages/climate-ref-core/src/climate_ref_core/summary.py b/packages/climate-ref-core/src/climate_ref_core/summary.py index da43c4402..685022bca 100644 --- a/packages/climate-ref-core/src/climate_ref_core/summary.py +++ b/packages/climate-ref-core/src/climate_ref_core/summary.py @@ -42,6 +42,14 @@ class DataRequirementSummary: which is what :mod:`climate_ref_core.reference_data` uses to work out where that dataset comes from. """ + fallback_source_types: tuple[str, ...] = () + """ + Values of the source types that may supply the requirement when ``source_type`` does not. + + :mod:`climate_ref_core.reference_data` reads this to resolve which registry carries a dataset, + so an obs4MIPs requirement served from the obs4REF registry is not reported as unobtainable. + """ + @frozen class RequirementSetSummary: @@ -105,7 +113,7 @@ def _extract_facet_values(filters: tuple[FacetFilter, ...], facet_name: str) -> return tuple(sorted(values)) -def _normalize_requirement_sets( +def normalize_requirement_sets( data_requirements: Sequence[DataRequirement] | Sequence[Sequence[DataRequirement]], ) -> list[Sequence[DataRequirement]]: """ @@ -162,6 +170,7 @@ def summarize_data_requirement(req: DataRequirement) -> DataRequirementSummary: frequencies=_extract_facet_values(req.filters, "frequency"), group_by=req.group_by, source_ids=_extract_facet_values(req.filters, "source_id"), + fallback_source_types=tuple(t.value for t in req.fallback_source_types), ) @@ -179,7 +188,7 @@ def summarize_diagnostic(diagnostic: Diagnostic) -> DiagnosticSummary: : A DiagnosticSummary with all requirement sets summarized. """ - requirement_sets = _normalize_requirement_sets(diagnostic.data_requirements) + requirement_sets = normalize_requirement_sets(diagnostic.data_requirements) set_summaries = [] for req_set in requirement_sets: diff --git a/packages/climate-ref-core/tests/unit/regression/test_report_store.py b/packages/climate-ref-core/tests/unit/regression/test_report_store.py new file mode 100644 index 000000000..613879e9d --- /dev/null +++ b/packages/climate-ref-core/tests/unit/regression/test_report_store.py @@ -0,0 +1,227 @@ +from pathlib import Path + +import pytest +from botocore.exceptions import ClientError, NoCredentialsError +from pytest_mock import MockerFixture + +from climate_ref_core.regression.report_store import ( + ReportStore, + build_report_store, +) +from climate_ref_core.regression.store import NativeStoreUnavailableError + +REMOTE_URL = "https://reports.example.com" +S3_ENDPOINT = "https://account.r2.cloudflarestorage.com" +BUCKET = "ref-baselines-reports" +KEY = "912/0c7e1d4abc12/index.html" +HTML = "text/html; charset=utf-8" + + +def _client_error(code: str, status: int, operation: str = "HeadObject") -> ClientError: + """Build a botocore ``ClientError`` with the given S3 error code / HTTP status.""" + return ClientError( + {"Error": {"Code": code, "Message": code}, "ResponseMetadata": {"HTTPStatusCode": status}}, + operation, + ) + + +@pytest.fixture() +def page(tmp_path: Path) -> Path: + p = tmp_path / "index.html" + p.write_text("

report

", encoding="utf-8") + return p + + +@pytest.fixture() +def local_store(tmp_path: Path) -> ReportStore: + return ReportStore(url=str(tmp_path / "reports")) + + +class _StubConfig: + """Minimal config double satisfying _ReportStoreConfigProtocol.""" + + def __init__(self, url: str, s3_endpoint_url: str = S3_ENDPOINT, bucket: str = BUCKET) -> None: + self._url = url + self._s3_endpoint_url = s3_endpoint_url + self._bucket = bucket + + @property + def url(self) -> str: + return self._url + + @property + def s3_endpoint_url(self) -> str: + return self._s3_endpoint_url + + @property + def bucket(self) -> str: + return self._bucket + + +class TestLocalStore: + def test_put_lands_the_file_under_the_key(self, local_store: ReportStore, page: Path) -> None: + url = local_store.put(KEY, page, HTML) + + assert local_store.root is not None + landed = local_store.root / KEY + assert landed.read_text(encoding="utf-8") == "

report

" + assert url == landed.absolute().as_uri() + assert url.startswith("file://") + assert url.endswith(KEY) + + def test_put_overwrites(self, local_store: ReportStore, page: Path, tmp_path: Path) -> None: + local_store.put(KEY, page, HTML) + newer = tmp_path / "newer.html" + newer.write_text("

newer

", encoding="utf-8") + + local_store.put(KEY, newer, HTML) + + assert local_store.root is not None + assert (local_store.root / KEY).read_text(encoding="utf-8") == "

newer

" + + @pytest.mark.parametrize("key", ["../x", "a/../../x", "/abs/index.html", "a b/index.html", ""]) + def test_put_rejects_an_unsafe_key(self, local_store: ReportStore, page: Path, key: str) -> None: + with pytest.raises(ValueError, match="report store key"): + local_store.put(key, page, HTML) + + def test_url_for_is_the_root_joined_with_the_key(self, local_store: ReportStore) -> None: + assert local_store.root is not None + assert local_store.url_for(KEY) == (local_store.root / KEY).absolute().as_uri() + + def test_preflight_creates_the_root(self, local_store: ReportStore) -> None: + local_store.preflight() + + assert local_store.root is not None + assert local_store.root.is_dir() + + def test_preflight_reports_an_unwritable_root( + self, local_store: ReportStore, mocker: MockerFixture + ) -> None: + mocker.patch("climate_ref_core.regression.store.os.access", return_value=False) + + with pytest.raises(NativeStoreUnavailableError, match="not writable"): + local_store.preflight() + + def test_preflight_reports_an_uncreatable_root(self, tmp_path: Path) -> None: + blocker = tmp_path / "blocker" + blocker.write_text("not a directory", encoding="utf-8") + store = ReportStore(url=str(blocker / "reports")) + + with pytest.raises(NativeStoreUnavailableError, match="could not be created"): + store.preflight() + + +class TestRemoteStore: + """The credentialed R2 write path, with a mocked boto3 client.""" + + def _store(self, mocker: MockerFixture, client, **kwargs) -> ReportStore: + mocker.patch("climate_ref_core.regression.store._s3_client", return_value=client) + return build_report_store(_StubConfig(REMOTE_URL, **kwargs), writable=True) + + def test_url_for_is_served_from_the_base_url(self) -> None: + store = ReportStore(url="https://h") + + assert store.url_for("1/a/index.html") == "https://h/1/a/index.html" + + def test_url_for_ignores_a_trailing_slash(self) -> None: + assert ReportStore(url="https://h/").url_for("1/a/index.html") == "https://h/1/a/index.html" + + def test_put_sets_the_content_type(self, mocker: MockerFixture, page: Path) -> None: + client = mocker.MagicMock() + store = self._store(mocker, client) + + url = store.put(KEY, page, HTML) + + client.upload_file.assert_called_once_with(str(page), BUCKET, KEY, ExtraArgs={"ContentType": HTML}) + assert url == f"{REMOTE_URL}/{KEY}" + + def test_put_without_credentials_is_read_only(self, page: Path) -> None: + store = ReportStore(url=REMOTE_URL) + + with pytest.raises(NotImplementedError, match="public-read store"): + store.put(KEY, page, HTML) + + def test_preflight_accepts_a_missing_probe(self, mocker: MockerFixture) -> None: + client = mocker.MagicMock() + client.head_object.side_effect = _client_error("404", 404) + store = self._store(mocker, client) + + store.preflight() + + client.head_object.assert_called_once() + + def test_preflight_reports_absent_credentials(self, mocker: MockerFixture) -> None: + client = mocker.MagicMock() + client.head_object.side_effect = NoCredentialsError() + store = self._store(mocker, client) + + with pytest.raises(NativeStoreUnavailableError, match="REF_REPORT_STORE_ACCESS_KEY_ID"): + store.preflight() + + def test_preflight_rejects_bad_credentials(self, mocker: MockerFixture) -> None: + client = mocker.MagicMock() + client.head_object.side_effect = _client_error("InvalidAccessKeyId", 401) + store = self._store(mocker, client) + + with pytest.raises(NativeStoreUnavailableError, match="REF_REPORT_STORE_ACCESS_KEY_ID"): + store.preflight() + + @pytest.mark.parametrize( + "code, status, expected", + [ + ("AccessDenied", 403, "access denied"), + ("InternalError", 500, "preflight failed"), + ], + ) + def test_preflight_reports_other_failures( + self, mocker: MockerFixture, code: str, status: int, expected: str + ) -> None: + client = mocker.MagicMock() + client.head_object.side_effect = _client_error(code, status) + store = self._store(mocker, client) + + with pytest.raises(NativeStoreUnavailableError, match=expected): + store.preflight() + + def test_a_read_only_remote_store_has_nothing_to_preflight(self) -> None: + ReportStore(url=REMOTE_URL).preflight() + + +class TestBuildReportStore: + def test_reads_the_report_store_env_vars(self, mocker: MockerFixture, monkeypatch) -> None: + monkeypatch.setenv("REF_REPORT_STORE_ACCESS_KEY_ID", "report-key") + monkeypatch.setenv("REF_REPORT_STORE_SECRET_ACCESS_KEY", "report-secret") + monkeypatch.setenv("REF_REPORT_STORE_PROFILE", "report-profile") + monkeypatch.setenv("REF_NATIVE_STORE_ACCESS_KEY_ID", "native-key") + monkeypatch.setenv("REF_NATIVE_STORE_SECRET_ACCESS_KEY", "native-secret") + monkeypatch.setenv("REF_NATIVE_STORE_PROFILE", "native-profile") + factory = mocker.patch( + "climate_ref_core.regression.store._s3_client", return_value=mocker.MagicMock() + ) + + store = build_report_store(_StubConfig(REMOTE_URL), writable=True) + store.put(KEY, Path(__file__), HTML) + + factory.assert_called_once_with(S3_ENDPOINT, "report-key", "report-secret", "report-profile") + + def test_read_only_needs_no_credentials(self) -> None: + store = build_report_store(_StubConfig(REMOTE_URL), writable=False) + + assert store.write is None + + @pytest.mark.parametrize( + "kwargs, expected", + [ + ({"s3_endpoint_url": ""}, "REF_REPORT_STORE_S3_ENDPOINT_URL"), + ({"bucket": ""}, "REF_REPORT_STORE_BUCKET"), + ], + ) + def test_missing_routing_names_the_report_store_env_var(self, kwargs, expected: str) -> None: + with pytest.raises(ValueError, match=expected): + build_report_store(_StubConfig(REMOTE_URL, **kwargs), writable=True) + + def test_a_local_store_is_writable_without_credentials(self, tmp_path: Path) -> None: + store = build_report_store(_StubConfig(str(tmp_path / "reports")), writable=True) + + assert store.write is None + assert store.root == tmp_path / "reports" diff --git a/packages/climate-ref-core/tests/unit/test_datasets.py b/packages/climate-ref-core/tests/unit/test_datasets.py index e2e6c9a58..4676e112a 100644 --- a/packages/climate-ref-core/tests/unit/test_datasets.py +++ b/packages/climate-ref-core/tests/unit/test_datasets.py @@ -143,8 +143,8 @@ def test_get_attr(self, dataset_collection_obs4mips): expected = dataset_collection_obs4mips.datasets.instance_id assert dataset_collection_obs4mips.instance_id.equals(expected) - def test_hash(self, dataset_collection_obs4mips, obs4mips_data_catalog, data_regression): - ts_datasets = obs4mips_data_catalog[obs4mips_data_catalog.variable_id == "ts"] + def test_hash(self, dataset_collection_obs4mips, obs4ref_data_catalog, data_regression): + ts_datasets = obs4ref_data_catalog[obs4ref_data_catalog.variable_id == "ts"] dataset_hash = hash(DatasetCollection(ts_datasets, "instance_id")) assert isinstance(dataset_hash, int) diff --git a/packages/climate-ref-core/tests/unit/test_datasets/dataset_collection_obs4mips_hash.yml b/packages/climate-ref-core/tests/unit/test_datasets/dataset_collection_obs4mips_hash.yml index 747f8fbd8..0be85b6d5 100644 --- a/packages/climate-ref-core/tests/unit/test_datasets/dataset_collection_obs4mips_hash.yml +++ b/packages/climate-ref-core/tests/unit/test_datasets/dataset_collection_obs4mips_hash.yml @@ -1,2 +1,2 @@ -2084895140671242963 +128483424965463584 ... diff --git a/packages/climate-ref-core/tests/unit/test_reference_data.py b/packages/climate-ref-core/tests/unit/test_reference_data.py index a57c3b165..9103a8181 100644 --- a/packages/climate-ref-core/tests/unit/test_reference_data.py +++ b/packages/climate-ref-core/tests/unit/test_reference_data.py @@ -78,8 +78,7 @@ def test_keys_are_read_per_source_type(self): found = source_ids_by_registry(manager) - # An obs4REF registry answers for obs4MIPs requirements too, since that is the - # source type its data is ingested under. + # The obs4REF registry supplies obs4MIPs requirements too assert found[(SourceDatasetType.obs4REF.value, "WECANN-1-0")] == ["obs4ref"] assert found[(SourceDatasetType.obs4MIPs.value, "WECANN-1-0")] == ["obs4ref"] @@ -164,6 +163,22 @@ def test_model_data_requirements_are_ignored(self): assert collect_required_reference_data([provider], _FakeManager({})) == [] + def test_declared_fallback_locates_the_registry(self): + manager = _FakeManager( + {"obs4ref": _FakeEntry([_obs4ref_key("WECANN-1-0", "gpp")], SourceDatasetType.obs4REF)} + ) + requirement = DataRequirement( + source_type=SourceDatasetType.PMPClimatology, + filters=(FacetFilter(facets={"source_id": "WECANN-1-0", "variable_id": "gpp"}),), + group_by=None, + fallback_source_types=(SourceDatasetType.obs4REF,), + ) + + (dataset,) = collect_required_reference_data([_provider([requirement])], manager) + + assert dataset.source_type == SourceDatasetType.PMPClimatology.value + assert dataset.registry_name == "obs4ref" + def test_variables_are_unioned_across_diagnostics(self): manager = _FakeManager({}) one = _provider([_requirement(SourceDatasetType.obs4MIPs, "ERA-5", "ta")], slug="one") diff --git a/packages/climate-ref-core/tests/unit/test_summary.py b/packages/climate-ref-core/tests/unit/test_summary.py index 194ba496a..64e04071f 100644 --- a/packages/climate-ref-core/tests/unit/test_summary.py +++ b/packages/climate-ref-core/tests/unit/test_summary.py @@ -10,12 +10,12 @@ from climate_ref_core.summary import ( DiagnosticReference, _extract_facet_values, - _normalize_requirement_sets, collect_by_source_type, collect_variables_by_experiment, format_diagnostic_markdown, format_overview_markdown, format_provider_markdown, + normalize_requirement_sets, summarize_data_requirement, summarize_diagnostic, summarize_provider, @@ -206,7 +206,7 @@ def test_flat_requirements(self): group_by=None, ), ) - result = _normalize_requirement_sets(reqs) + result = normalize_requirement_sets(reqs) assert len(result) == 1 assert len(result[0]) == 1 assert isinstance(result[0][0], DataRequirement) @@ -229,18 +229,18 @@ def test_nested_or_requirements(self): ), ), ) - result = _normalize_requirement_sets(reqs) + result = normalize_requirement_sets(reqs) assert len(result) == 2 assert result[0][0].source_type == SourceDatasetType.CMIP6 assert result[1][0].source_type == SourceDatasetType.CMIP7 def test_empty_requirements(self): - result = _normalize_requirement_sets(()) + result = normalize_requirement_sets(()) assert result == [] def test_invalid_type_raises(self): with pytest.raises(TypeError, match="Expected DataRequirement"): - _normalize_requirement_sets((42,)) + normalize_requirement_sets((42,)) class TestSummarizeDataRequirement: diff --git a/packages/climate-ref-esmvaltool/src/climate_ref_esmvaltool/diagnostics/sea_ice_sensitivity.py b/packages/climate-ref-esmvaltool/src/climate_ref_esmvaltool/diagnostics/sea_ice_sensitivity.py index bf3120076..c675cac71 100644 --- a/packages/climate-ref-esmvaltool/src/climate_ref_esmvaltool/diagnostics/sea_ice_sensitivity.py +++ b/packages/climate-ref-esmvaltool/src/climate_ref_esmvaltool/diagnostics/sea_ice_sensitivity.py @@ -1,3 +1,4 @@ +import copy from pathlib import Path import pandas @@ -15,7 +16,7 @@ from climate_ref_core.esgf import CMIP6Request, CMIP7Request from climate_ref_core.metric_values.typing import FileDefinition from climate_ref_core.pycmec.metric import CMECMetric, MetricCV -from climate_ref_core.pycmec.output import CMECOutput +from climate_ref_core.pycmec.output import CMECOutput, OutputCV from climate_ref_core.testing import TestCase, TestDataSpecification from climate_ref_esmvaltool.diagnostics.base import ESMValToolDiagnostic, get_cmip_source_type from climate_ref_esmvaltool.recipe import dataframe_to_recipe @@ -30,6 +31,7 @@ class SeaIceSensitivity(ESMValToolDiagnostic): name = "Sea ice sensitivity" slug = "sea-ice-sensitivity" base_recipe = "recipe_seaice_sensitivity.yml" + version = 2 data_requirements = ( ( @@ -132,7 +134,8 @@ class SeaIceSensitivity(ESMValToolDiagnostic): for region in ("arctic", "antarctic") ) + tuple( FileDefinition( - file_pattern=f"work/{region}/sea_ice_sensitivity_script/plotted_values.csv", + # ESMValTool v2.15 registers this file in its provenance without the .csv suffix. + file_pattern=f"work/{region}/sea_ice_sensitivity_script/data_values*", dimensions={"region": region}, ) for region in ("arctic", "antarctic") @@ -193,25 +196,33 @@ def update_recipe( """Update the recipe.""" cmip_source = get_cmip_source_type(input_files) recipe_variables = dataframe_to_recipe(input_files[cmip_source]) - - if cmip_source == SourceDatasetType.CMIP7: - # CMIP7: use per-variable additional_datasets to preserve correct branding_suffix - recipe["datasets"] = [] - for diagnostic in recipe["diagnostics"].values(): - for var_name, variable in diagnostic.get("variables", {}).items(): - short_name = variable.get("short_name", var_name) - if short_name in recipe_variables: - datasets = recipe_variables[short_name]["additional_datasets"] - for ds in datasets: - ds.pop("mip", None) - ds["timerange"] = "1979/2014" - variable["additional_datasets"] = datasets - else: - datasets = recipe_variables["tas"]["additional_datasets"] - for dataset in datasets: - dataset.pop("mip") + for variable in recipe_variables.values(): + for dataset in variable["additional_datasets"]: + dataset.pop("mip", None) dataset["timerange"] = "1979/2014" - recipe["datasets"] = datasets + + # The REF supplies the models from the solve and has no ESMValTool observations available, + # so drop the datasets the recipe carries and the anchors holding them. + for key in ( + "datasets", + "model_defaults", + "model_datasets", + "obs_defaults", + "tasa_obs", + "arctic_siconc_obs", + "antarctic_siconc_obs", + ): + recipe.pop(key, None) + + for diagnostic in recipe["diagnostics"].values(): + variables = diagnostic["variables"] + for name in list(variables): + if name in recipe_variables: + variables[name]["additional_datasets"] = copy.deepcopy( + recipe_variables[name]["additional_datasets"] + ) + else: + del variables[name] @staticmethod def format_result( @@ -231,22 +242,33 @@ def format_result( "region": {}, "metric": {}, } + dimensions = metric_args[MetricCV.DIMENSIONS.value] for region in "antarctic", "arctic": df = pd.read_csv( - result_dir / "work" / region / "sea_ice_sensitivity_script" / "plotted_values.csv" + result_dir / "work" / region / "sea_ice_sensitivity_script" / "data_values.csv", + header=[0, 1, 2], + index_col=0, ) - df = df.rename(columns={"Unnamed: 0": "source_id"}).drop(columns=["label"]) - metric_args[MetricCV.DIMENSIONS.value]["region"][region] = {} - for metric in df.columns[1:]: - metric_args[MetricCV.DIMENSIONS.value]["metric"][metric] = {} - for row in df.itertuples(index=False): - source_id = row.source_id - metric_args[MetricCV.DIMENSIONS.value]["source_id"][source_id] = {} - for metric, value in zip(df.columns[1:], row[1:]): - if source_id not in metric_args[MetricCV.RESULTS.value]: - metric_args[MetricCV.RESULTS.value][source_id] = {} - if region not in metric_args[MetricCV.RESULTS.value][source_id]: - metric_args[MetricCV.RESULTS.value][source_id][region] = {} - metric_args[MetricCV.RESULTS.value][source_id][region][metric] = value + is_type = df.columns.get_level_values("statistic") == "type" + is_model = df.loc[:, is_type].iloc[:, 0] == "model" + # The REF solve covers a single period, so keep the last one if the script adds more. + period = str(df.columns.get_level_values("period")[-1]) + values = df.loc[is_model, period] + + dimensions["region"][region] = {} + for regression, statistic in values.columns: + dimensions["metric"][f"{regression}_{statistic}"] = {} + for source_id, row in values.iterrows(): + dimensions["source_id"][source_id] = {} + results = metric_args[MetricCV.RESULTS.value].setdefault(source_id, {}).setdefault(region, {}) + for (regression, statistic), value in row.items(): + results[f"{regression}_{statistic}"] = float(value) + + # Restore the data_values suffix + data = output_args[OutputCV.DATA.value] + for key in [key for key in data if key.endswith("/data_values")]: + entry = data.pop(key) + entry[OutputCV.FILENAME.value] = f"{entry[OutputCV.FILENAME.value]}.csv" + data[f"{key}.csv"] = entry return CMECMetric.model_validate(metric_args), CMECOutput.model_validate(output_args) diff --git a/packages/climate-ref-esmvaltool/tests/test-data/sea-ice-sensitivity/cmip6/manifest.json b/packages/climate-ref-esmvaltool/tests/test-data/sea-ice-sensitivity/cmip6/manifest.json index d64db0bcf..d1c3a90b4 100644 --- a/packages/climate-ref-esmvaltool/tests/test-data/sea-ice-sensitivity/cmip6/manifest.json +++ b/packages/climate-ref-esmvaltool/tests/test-data/sea-ice-sensitivity/cmip6/manifest.json @@ -1,55 +1,55 @@ { "catalog_hash": "ed2db5a8a44c55840961c2a0a30fa1160cfa42ab", "committed": { - "diagnostic.json": "1e9c270e88ad1395978103851bdb068629fd90e265229baa7d76c0310853982b", - "output.json": "0addb1511d0f758554aa7caac92ee3c254d279e2cb7da71e326dcdc191169939", + "diagnostic.json": "8dffe46455b90b10d172ff2e9f85d0f959a1efc69277e068e0830c1b879d89ee", + "output.json": "f3b3b0f75f134bb26a730e5f51ce20acd253e373fd07e15b62939963652d4775", "series.json": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570" }, - "diagnostic_version": 1, + "diagnostic_version": 2, "native": { "diagnostic.json": { - "sha256": "a9fce0fa39fbba0cdd17aca8264f0d272f6e2b3efb0412cf851b958a4a6a08e2", - "size": 1198 + "sha256": "2119b8fe5751c25caa4b82e3bc34f6ef42ea15a3cf1cda5b0730cf3d8542848d", + "size": 2317 }, "executions/recipe/index.html": { - "sha256": "93a956c8c0c2df28590a69ac37e2b78f67797097e8ae1167ecc21d2e06d76261", - "size": 15915 + "sha256": "ce0b44849e6f67626d1d77bc4713bae8c62d7884eb32946b0bd38ee06f7d428b", + "size": 15971 }, "executions/recipe/plots/antarctic/sea_ice_sensitivity_script/png/Annual Antarctic sea ice sensitivity.png": { - "sha256": "4f06a0229cc45c5fa70b9ca1a8e058334c5e660cceecb9ab4ef80fc891c07412", - "size": 15933 + "sha256": "c0c574544ccab6542148bfbcadd6be187f53e2db7816e00950fd1350e4ea3d59", + "size": 16406 }, "executions/recipe/plots/antarctic/sea_ice_sensitivity_script/png/Annual Antarctic sea ice trends.png": { - "sha256": "95f77ffa79d400184a0c188503026a754cad9a028ad6428e16f044c6ae11de2f", - "size": 37229 + "sha256": "7278db8150586ae7080715a5ce9aa5985b18556a6a1cd779b9b9411fc84f4d2e", + "size": 39561 }, "executions/recipe/plots/arctic/sea_ice_sensitivity_script/png/September Arctic sea ice sensitivity.png": { - "sha256": "6b649635fc99c069f3fa4c5708eba7234f5013a5cc15d6e0d5b60949758d6f33", - "size": 21396 + "sha256": "5693bee5d6810c0d8c58d7adf0c7ecc80adbc01c2d84c0b689134104b143133b", + "size": 20488 }, "executions/recipe/plots/arctic/sea_ice_sensitivity_script/png/September Arctic sea ice trends.png": { - "sha256": "8efdcc711f0b1f373d4069f7ff9486ba0f31a09e72c8d1cd310c5ac9cce9f652", - "size": 36062 + "sha256": "c4a54dfc60fc88af4ff633d8067f76aa977d1b40a4083d331c653612f370eaa4", + "size": 39996 }, "executions/recipe/run/antarctic/sea_ice_sensitivity_script/diagnostic_provenance.yml": { - "sha256": "0e8c755c7b7939907fb2bb38e9a845de20f7d74c075967a335d21410de87f187", - "size": 1476 + "sha256": "aa316a3d7211e624f50d97d1716570f850eb9e32a70341f8f3f2dfc7edb8fddc", + "size": 1469 }, "executions/recipe/run/arctic/sea_ice_sensitivity_script/diagnostic_provenance.yml": { - "sha256": "c12c3034076bf312f37bf26c2539ca7fe97fe1ed8793687eb08f4838f4b66de6", - "size": 1532 + "sha256": "452842ae27218a853d5d551e516f8ab7bc6e94cc09fc25e950e90d72fafb64cd", + "size": 1560 }, - "executions/recipe/work/antarctic/sea_ice_sensitivity_script/plotted_values.csv": { - "sha256": "832fccab6e7efd626a2bc56c9ea7e025279186bbc16a02f2f6783ae16336e38b", - "size": 225 + "executions/recipe/work/antarctic/sea_ice_sensitivity_script/data_values.csv": { + "sha256": "f717d22563f878c90c3c5afb203ce30930761db09f1ca046de74fb1314f28e65", + "size": 715 }, - "executions/recipe/work/arctic/sea_ice_sensitivity_script/plotted_values.csv": { - "sha256": "c0b13303ee5bfb24f343967d33f4954e47a10b8d10415b9d554135af9b0c96ca", - "size": 224 + "executions/recipe/work/arctic/sea_ice_sensitivity_script/data_values.csv": { + "sha256": "2beee01f0310e8cfd93570e09e2fb36adafeb89456d4ac926c1fc2a448c83d28", + "size": 719 }, "output.json": { - "sha256": "2fc746e657b5cd596eafed2925eb8e6dc9dafe0c388a143640d33b6681122e1d", - "size": 2912 + "sha256": "c6f41e586979162b667cb4b3bffa263652ac6bae0dc625fed9a4c35a9800c271", + "size": 2929 }, "series.json": { "sha256": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", @@ -57,5 +57,5 @@ } }, "schema": 2, - "test_case_version": 1 + "test_case_version": 2 } diff --git a/packages/climate-ref-esmvaltool/tests/test-data/sea-ice-sensitivity/cmip6/regression/diagnostic.json b/packages/climate-ref-esmvaltool/tests/test-data/sea-ice-sensitivity/cmip6/regression/diagnostic.json index 2c8032616..cb9a7726f 100644 --- a/packages/climate-ref-esmvaltool/tests/test-data/sea-ice-sensitivity/cmip6/regression/diagnostic.json +++ b/packages/climate-ref-esmvaltool/tests/test-data/sea-ice-sensitivity/cmip6/regression/diagnostic.json @@ -10,11 +10,18 @@ "metric" ], "metric": { - "annual_siconc_trend": {}, - "annual_tas_trend": {}, - "direct_p_val": {}, - "direct_r_val": {}, - "direct_sensitivity_(notz-style)": {} + "gmst_over_time_p_value": {}, + "gmst_over_time_r_value": {}, + "gmst_over_time_slope": {}, + "gmst_over_time_std_err_slope": {}, + "sia_over_gmst_p_value": {}, + "sia_over_gmst_r_value": {}, + "sia_over_gmst_slope": {}, + "sia_over_gmst_std_err_slope": {}, + "sia_over_time_p_value": {}, + "sia_over_time_r_value": {}, + "sia_over_time_slope": {}, + "sia_over_time_std_err_slope": {} }, "region": { "antarctic": {}, @@ -31,18 +38,32 @@ "historical": { "CanESM5": { "antarctic": { - "annual_siconc_trend": -0.003315054, - "annual_tas_trend": 0.03272226, - "direct_p_val": 0.3522661, - "direct_r_val": -0.159671, - "direct_sensitivity_(notz-style)": -0.2176355 + "gmst_over_time_p_value": 1.181736e-16, + "gmst_over_time_r_value": 0.9329817, + "gmst_over_time_slope": 0.03272226, + "gmst_over_time_std_err_slope": 0.002164918, + "sia_over_gmst_p_value": 0.3522657, + "sia_over_gmst_r_value": -0.159671, + "sia_over_gmst_slope": -0.2176355, + "sia_over_gmst_std_err_slope": 0.2307577, + "sia_over_time_p_value": 0.6877782, + "sia_over_time_r_value": -0.06934527, + "sia_over_time_slope": -0.003315054, + "sia_over_time_std_err_slope": 0.008178762 }, "arctic": { - "annual_siconc_trend": -0.07236914, - "annual_tas_trend": 0.03272226, - "direct_p_val": 3.949451e-12, - "direct_r_val": -0.872809, - "direct_sensitivity_(notz-style)": -2.066191 + "gmst_over_time_p_value": 1.181736e-16, + "gmst_over_time_r_value": 0.9329817, + "gmst_over_time_slope": 0.03272226, + "gmst_over_time_std_err_slope": 0.002164918, + "sia_over_gmst_p_value": 3.949456e-12, + "sia_over_gmst_r_value": -0.872809, + "sia_over_gmst_slope": -2.066191, + "sia_over_gmst_std_err_slope": 0.1981467, + "sia_over_time_p_value": 4.576936e-12, + "sia_over_time_r_value": -0.8716297, + "sia_over_time_slope": -0.07236914, + "sia_over_time_std_err_slope": 0.006979499 } } } diff --git a/packages/climate-ref-esmvaltool/tests/test-data/sea-ice-sensitivity/cmip6/regression/output.json b/packages/climate-ref-esmvaltool/tests/test-data/sea-ice-sensitivity/cmip6/regression/output.json index 16b043dd2..01cda3620 100644 --- a/packages/climate-ref-esmvaltool/tests/test-data/sea-ice-sensitivity/cmip6/regression/output.json +++ b/packages/climate-ref-esmvaltool/tests/test-data/sea-ice-sensitivity/cmip6/regression/output.json @@ -1,19 +1,19 @@ { "data": { - "executions/recipe/work/antarctic/sea_ice_sensitivity_script/plotted_values.csv": { + "executions/recipe/work/antarctic/sea_ice_sensitivity_script/data_values.csv": { "description": "", "dimensions": { "region": "antarctic" }, - "filename": "executions/recipe/work/antarctic/sea_ice_sensitivity_script/plotted_values.csv", + "filename": "executions/recipe/work/antarctic/sea_ice_sensitivity_script/data_values.csv", "long_name": "Annual (not decadal) figures" }, - "executions/recipe/work/arctic/sea_ice_sensitivity_script/plotted_values.csv": { + "executions/recipe/work/arctic/sea_ice_sensitivity_script/data_values.csv": { "description": "", "dimensions": { "region": "arctic" }, - "filename": "executions/recipe/work/arctic/sea_ice_sensitivity_script/plotted_values.csv", + "filename": "executions/recipe/work/arctic/sea_ice_sensitivity_script/data_values.csv", "long_name": "Annual (not decadal) figures" } }, @@ -51,7 +51,7 @@ "region": "arctic" }, "filename": "executions/recipe/plots/arctic/sea_ice_sensitivity_script/png/September Arctic sea ice sensitivity.png", - "long_name": "Sensitivity of sea ice area to annual mean global warming.Mean (dashed), standard deviation (shaded) and plausible values from 1979-2014." + "long_name": "Sensitivity of sea ice area to annual mean global warming.\nMean (dashed), standard deviation (shaded) and plausible (dotted) values from 1979-2014 are shown in grey." }, "executions/recipe/plots/arctic/sea_ice_sensitivity_script/png/September Arctic sea ice trends.png": { "description": "", diff --git a/packages/climate-ref-esmvaltool/tests/test-data/sea-ice-sensitivity/cmip7/manifest.json b/packages/climate-ref-esmvaltool/tests/test-data/sea-ice-sensitivity/cmip7/manifest.json index f237e17b1..a87e54b2c 100644 --- a/packages/climate-ref-esmvaltool/tests/test-data/sea-ice-sensitivity/cmip7/manifest.json +++ b/packages/climate-ref-esmvaltool/tests/test-data/sea-ice-sensitivity/cmip7/manifest.json @@ -1,12 +1,61 @@ { "catalog_hash": "2f092e0f5e2623c8d4fa077d6ce59043ae956260", "committed": { - "diagnostic.json": "03a1c1bae4bd062a77ae76682eb4963b33fbffa47051f1d78fb6ac585028a643", - "output.json": "0addb1511d0f758554aa7caac92ee3c254d279e2cb7da71e326dcdc191169939", + "diagnostic.json": "9fa984d14f391fd5e574159b702bd8c4881345f986038c3fdf6f216292d3e2b0", + "output.json": "f3b3b0f75f134bb26a730e5f51ce20acd253e373fd07e15b62939963652d4775", "series.json": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570" }, - "diagnostic_version": 1, - "native": {}, + "diagnostic_version": 2, + "native": { + "diagnostic.json": { + "sha256": "e96e3d780172d89db6d4950bdfa0dd2e44f6ef7e9ce4a8f5f2b7eac93e18cf41", + "size": 2318 + }, + "executions/recipe/index.html": { + "sha256": "ce0b44849e6f67626d1d77bc4713bae8c62d7884eb32946b0bd38ee06f7d428b", + "size": 15971 + }, + "executions/recipe/plots/antarctic/sea_ice_sensitivity_script/png/Annual Antarctic sea ice sensitivity.png": { + "sha256": "a4b906b9a6e64a9ca014739f5edf82732fdd5be34deddfd2b3656762fc5d5ff9", + "size": 16582 + }, + "executions/recipe/plots/antarctic/sea_ice_sensitivity_script/png/Annual Antarctic sea ice trends.png": { + "sha256": "9fdaa61e8dc69e359e75cf373aa69859e22269f428bd518e0f6fa68c04d25cc9", + "size": 39400 + }, + "executions/recipe/plots/arctic/sea_ice_sensitivity_script/png/September Arctic sea ice sensitivity.png": { + "sha256": "283b6bbbeaae0f135c7b65bf6b077fee6024ead20be1557a0f9ac29fa71d740d", + "size": 20451 + }, + "executions/recipe/plots/arctic/sea_ice_sensitivity_script/png/September Arctic sea ice trends.png": { + "sha256": "cff577a1b2c51663154f50f4d0c1734a39386c7d629f867fdb43fb8a02d24d03", + "size": 40017 + }, + "executions/recipe/run/antarctic/sea_ice_sensitivity_script/diagnostic_provenance.yml": { + "sha256": "cfa74bdac799454269a1ed181e2bb4671a6c2c124d7b9737ac494c3b10bd5107", + "size": 1532 + }, + "executions/recipe/run/arctic/sea_ice_sensitivity_script/diagnostic_provenance.yml": { + "sha256": "61e81ad16557de95a6d4103119f88cf0c1a85f3f945fbad5ea053353e62b6d08", + "size": 1623 + }, + "executions/recipe/work/antarctic/sea_ice_sensitivity_script/data_values.csv": { + "sha256": "d764824f57f8ec20e167554993d377b7a25625985ceeb11f31da788243d5784b", + "size": 715 + }, + "executions/recipe/work/arctic/sea_ice_sensitivity_script/data_values.csv": { + "sha256": "aa18e899753ab92b001df66eecd494ddc05c1076d54a7a6a8c6d9a233cb17fc1", + "size": 721 + }, + "output.json": { + "sha256": "c6f41e586979162b667cb4b3bffa263652ac6bae0dc625fed9a4c35a9800c271", + "size": 2929 + }, + "series.json": { + "sha256": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "size": 2 + } + }, "schema": 2, - "test_case_version": 1 + "test_case_version": 2 } diff --git a/packages/climate-ref-esmvaltool/tests/test-data/sea-ice-sensitivity/cmip7/regression/diagnostic.json b/packages/climate-ref-esmvaltool/tests/test-data/sea-ice-sensitivity/cmip7/regression/diagnostic.json index 49eb3beab..717240f4b 100644 --- a/packages/climate-ref-esmvaltool/tests/test-data/sea-ice-sensitivity/cmip7/regression/diagnostic.json +++ b/packages/climate-ref-esmvaltool/tests/test-data/sea-ice-sensitivity/cmip7/regression/diagnostic.json @@ -10,11 +10,18 @@ "metric" ], "metric": { - "annual_siconc_trend": {}, - "annual_tas_trend": {}, - "direct_p_val": {}, - "direct_r_val": {}, - "direct_sensitivity_(notz-style)": {} + "gmst_over_time_p_value": {}, + "gmst_over_time_r_value": {}, + "gmst_over_time_slope": {}, + "gmst_over_time_std_err_slope": {}, + "sia_over_gmst_p_value": {}, + "sia_over_gmst_r_value": {}, + "sia_over_gmst_slope": {}, + "sia_over_gmst_std_err_slope": {}, + "sia_over_time_p_value": {}, + "sia_over_time_r_value": {}, + "sia_over_time_slope": {}, + "sia_over_time_std_err_slope": {} }, "region": { "antarctic": {}, @@ -31,18 +38,32 @@ "historical": { "CanESM5": { "antarctic": { - "annual_siconc_trend": -0.003316542, - "annual_tas_trend": 0.03273005, - "direct_p_val": 0.3521369, - "direct_r_val": -0.1597133, - "direct_sensitivity_(notz-style)": -0.2176574 + "gmst_over_time_p_value": 1.169205e-16, + "gmst_over_time_r_value": 0.933025, + "gmst_over_time_slope": 0.03273005, + "gmst_over_time_std_err_slope": 0.002164657, + "sia_over_gmst_p_value": 0.3521365, + "sia_over_gmst_r_value": -0.1597134, + "sia_over_gmst_slope": -0.2176575, + "sia_over_gmst_std_err_slope": 0.2307182, + "sia_over_time_p_value": 0.6876532, + "sia_over_time_r_value": -0.06937449, + "sia_over_time_slope": -0.003316542, + "sia_over_time_std_err_slope": 0.008178971 }, "arctic": { - "annual_siconc_trend": -0.07238201, - "annual_tas_trend": 0.03273005, - "direct_p_val": 3.959278e-12, - "direct_r_val": -0.8727892, - "direct_sensitivity_(notz-style)": -2.0661 + "gmst_over_time_p_value": 1.169205e-16, + "gmst_over_time_r_value": 0.933025, + "gmst_over_time_slope": 0.03273005, + "gmst_over_time_std_err_slope": 0.002164657, + "sia_over_gmst_p_value": 3.959334e-12, + "sia_over_gmst_r_value": -0.8727891, + "sia_over_gmst_slope": -2.0661, + "sia_over_gmst_std_err_slope": 0.1981568, + "sia_over_time_p_value": 4.573249e-12, + "sia_over_time_r_value": -0.8716361, + "sia_over_time_slope": -0.07238201, + "sia_over_time_std_err_slope": 0.006980524 } } } diff --git a/packages/climate-ref-esmvaltool/tests/test-data/sea-ice-sensitivity/cmip7/regression/output.json b/packages/climate-ref-esmvaltool/tests/test-data/sea-ice-sensitivity/cmip7/regression/output.json index 16b043dd2..01cda3620 100644 --- a/packages/climate-ref-esmvaltool/tests/test-data/sea-ice-sensitivity/cmip7/regression/output.json +++ b/packages/climate-ref-esmvaltool/tests/test-data/sea-ice-sensitivity/cmip7/regression/output.json @@ -1,19 +1,19 @@ { "data": { - "executions/recipe/work/antarctic/sea_ice_sensitivity_script/plotted_values.csv": { + "executions/recipe/work/antarctic/sea_ice_sensitivity_script/data_values.csv": { "description": "", "dimensions": { "region": "antarctic" }, - "filename": "executions/recipe/work/antarctic/sea_ice_sensitivity_script/plotted_values.csv", + "filename": "executions/recipe/work/antarctic/sea_ice_sensitivity_script/data_values.csv", "long_name": "Annual (not decadal) figures" }, - "executions/recipe/work/arctic/sea_ice_sensitivity_script/plotted_values.csv": { + "executions/recipe/work/arctic/sea_ice_sensitivity_script/data_values.csv": { "description": "", "dimensions": { "region": "arctic" }, - "filename": "executions/recipe/work/arctic/sea_ice_sensitivity_script/plotted_values.csv", + "filename": "executions/recipe/work/arctic/sea_ice_sensitivity_script/data_values.csv", "long_name": "Annual (not decadal) figures" } }, @@ -51,7 +51,7 @@ "region": "arctic" }, "filename": "executions/recipe/plots/arctic/sea_ice_sensitivity_script/png/September Arctic sea ice sensitivity.png", - "long_name": "Sensitivity of sea ice area to annual mean global warming.Mean (dashed), standard deviation (shaded) and plausible values from 1979-2014." + "long_name": "Sensitivity of sea ice area to annual mean global warming.\nMean (dashed), standard deviation (shaded) and plausible (dotted) values from 1979-2014 are shown in grey." }, "executions/recipe/plots/arctic/sea_ice_sensitivity_script/png/September Arctic sea ice trends.png": { "description": "", diff --git a/packages/climate-ref-esmvaltool/tests/unit/diagnostics/recipes/recipe_sea_ice_sensitivity_cmip6.yml b/packages/climate-ref-esmvaltool/tests/unit/diagnostics/recipes/recipe_sea_ice_sensitivity_cmip6.yml index 8b557ac7e..ba667cecb 100644 --- a/packages/climate-ref-esmvaltool/tests/unit/diagnostics/recipes/recipe_sea_ice_sensitivity_cmip6.yml +++ b/packages/climate-ref-esmvaltool/tests/unit/diagnostics/recipes/recipe_sea_ice_sensitivity_cmip6.yml @@ -23,48 +23,7 @@ documentation: - blockley_ed maintainer: - parsons_naomi -defaults: - ensemble: r1i1p1f1 - exp: historical - grid: gn - project: CMIP6 -datasets: -- project: CMIP6 - activity: CMIP - dataset: ACCESS-ESM1-5 - ensemble: r1i1p1f1 - institute: CSIRO - exp: historical - grid: gn - timerange: 1979/2014 -- project: CMIP6 - activity: CMIP - dataset: MPI-ESM1-2-LR - ensemble: r1i1p1f1 - institute: MPI-M - exp: historical - grid: gn - timerange: 1979/2014 -- project: CMIP6 - activity: CMIP - dataset: CESM2 - ensemble: r1i1p1f1 - institute: NCAR - exp: historical - grid: gn - timerange: 1979/2014 preprocessors: - extract_test_period: - extract_time: - start_day: 1 - start_month: 1 - start_year: 1979 - end_day: 31 - end_month: 12 - end_year: 2014 - extract_sept: - extract_month: - month: 9 nh_total_area: extract_region: start_longitude: 0 @@ -92,14 +51,10 @@ preprocessors: annual_statistics: operator: mean keep_group_coordinates: true + extract_sept: + extract_month: + month: 9 pp_arctic_sept_sea_ice: - extract_time: - start_day: 1 - start_month: 1 - start_year: 1979 - end_day: 31 - end_month: 12 - end_year: 2014 extract_month: month: 9 extract_region: @@ -112,13 +67,6 @@ preprocessors: convert_units: units: 1e6 km2 pp_antarctic_avg_ann_sea_ice: - extract_time: - start_day: 1 - start_month: 1 - start_year: 1979 - end_day: 31 - end_month: 12 - end_year: 2014 annual_statistics: operator: mean keep_group_coordinates: true @@ -132,13 +80,6 @@ preprocessors: convert_units: units: 1e6 km2 pp_avg_ann_global_temp: - extract_time: - start_day: 1 - start_month: 1 - start_year: 1979 - end_day: 31 - end_month: 12 - end_year: 2014 area_statistics: operator: mean annual_statistics: @@ -152,34 +93,70 @@ diagnostics: siconc: preprocessor: pp_arctic_sept_sea_ice mip: SImon + additional_datasets: + - project: CMIP6 + activity: CMIP + dataset: ACCESS-ESM1-5 + ensemble: r1i1p1f1 + institute: CSIRO + exp: historical + grid: gn + timerange: 1979/2014 + - project: CMIP6 + activity: CMIP + dataset: MPI-ESM1-2-LR + ensemble: r1i1p1f1 + institute: MPI-M + exp: historical + grid: gn + timerange: 1979/2014 + - project: CMIP6 + activity: CMIP + dataset: CESM2 + ensemble: r1i1p1f1 + institute: NCAR + exp: historical + grid: gn + timerange: 1979/2014 tas: preprocessor: pp_avg_ann_global_temp mip: Amon + additional_datasets: + - project: CMIP6 + activity: CMIP + dataset: ACCESS-ESM1-5 + ensemble: r1i1p1f1 + institute: CSIRO + exp: historical + grid: gn + timerange: 1979/2014 + - project: CMIP6 + activity: CMIP + dataset: MPI-ESM1-2-LR + ensemble: r1i1p1f1 + institute: MPI-M + exp: historical + grid: gn + timerange: 1979/2014 + - project: CMIP6 + activity: CMIP + dataset: CESM2 + ensemble: r1i1p1f1 + institute: NCAR + exp: historical + grid: gn + timerange: 1979/2014 scripts: sea_ice_sensitivity_script: script: seaice/seaice_sensitivity.py observations: - observation period: 1979-2014 - sea ice sensitivity (Notz-style plot): + observation_period: + start_year: 1979 + end_year: 2014 + sea_ice_sensitivity: mean: -4.01 - standard deviation: 0.32 - plausible range: 1.28 - annual trends (Roach-style plot): - first point: - GMST trend: null - SIA trend: null - Pearson CC of SIA over GMST: null - significance of SIA over GMST: null - second point: - GMST trend: null - SIA trend: null - Pearson CC of SIA over GMST: null - significance of SIA over GMST: null - third point: - GMST trend: null - SIA trend: null - Pearson CC of SIA over GMST: null - significance of SIA over GMST: null + standard_deviation: 0.32 + plausible_range: 1.28 antarctic: description: Plots annual mean sea ice sensitivity below 0 latitude in millions of square kilometres @@ -187,31 +164,59 @@ diagnostics: siconc: preprocessor: pp_antarctic_avg_ann_sea_ice mip: SImon + additional_datasets: + - project: CMIP6 + activity: CMIP + dataset: ACCESS-ESM1-5 + ensemble: r1i1p1f1 + institute: CSIRO + exp: historical + grid: gn + timerange: 1979/2014 + - project: CMIP6 + activity: CMIP + dataset: MPI-ESM1-2-LR + ensemble: r1i1p1f1 + institute: MPI-M + exp: historical + grid: gn + timerange: 1979/2014 + - project: CMIP6 + activity: CMIP + dataset: CESM2 + ensemble: r1i1p1f1 + institute: NCAR + exp: historical + grid: gn + timerange: 1979/2014 tas: preprocessor: pp_avg_ann_global_temp mip: Amon + additional_datasets: + - project: CMIP6 + activity: CMIP + dataset: ACCESS-ESM1-5 + ensemble: r1i1p1f1 + institute: CSIRO + exp: historical + grid: gn + timerange: 1979/2014 + - project: CMIP6 + activity: CMIP + dataset: MPI-ESM1-2-LR + ensemble: r1i1p1f1 + institute: MPI-M + exp: historical + grid: gn + timerange: 1979/2014 + - project: CMIP6 + activity: CMIP + dataset: CESM2 + ensemble: r1i1p1f1 + institute: NCAR + exp: historical + grid: gn + timerange: 1979/2014 scripts: sea_ice_sensitivity_script: script: seaice/seaice_sensitivity.py - observations: - observation period: null - sea ice sensitivity (Notz-style plot): - mean: null - standard deviation: null - plausible range: null - annual trends (Roach-style plot): - first point: - GMST trend: null - SIA trend: null - Pearson CC of SIA over GMST: null - significance of SIA over GMST: null - second point: - GMST trend: null - SIA trend: null - Pearson CC of SIA over GMST: null - significance of SIA over GMST: null - third point: - GMST trend: null - SIA trend: null - Pearson CC of SIA over GMST: null - significance of SIA over GMST: null diff --git a/packages/climate-ref-esmvaltool/tests/unit/diagnostics/recipes/recipe_sea_ice_sensitivity_cmip7.yml b/packages/climate-ref-esmvaltool/tests/unit/diagnostics/recipes/recipe_sea_ice_sensitivity_cmip7.yml index 48479804a..e767efaaa 100644 --- a/packages/climate-ref-esmvaltool/tests/unit/diagnostics/recipes/recipe_sea_ice_sensitivity_cmip7.yml +++ b/packages/climate-ref-esmvaltool/tests/unit/diagnostics/recipes/recipe_sea_ice_sensitivity_cmip7.yml @@ -23,24 +23,7 @@ documentation: - blockley_ed maintainer: - parsons_naomi -defaults: - ensemble: r1i1p1f1 - exp: historical - grid: gn - project: CMIP6 -datasets: [] preprocessors: - extract_test_period: - extract_time: - start_day: 1 - start_month: 1 - start_year: 1979 - end_day: 31 - end_month: 12 - end_year: 2014 - extract_sept: - extract_month: - month: 9 nh_total_area: extract_region: start_longitude: 0 @@ -68,14 +51,10 @@ preprocessors: annual_statistics: operator: mean keep_group_coordinates: true + extract_sept: + extract_month: + month: 9 pp_arctic_sept_sea_ice: - extract_time: - start_day: 1 - start_month: 1 - start_year: 1979 - end_day: 31 - end_month: 12 - end_year: 2014 extract_month: month: 9 extract_region: @@ -88,13 +67,6 @@ preprocessors: convert_units: units: 1e6 km2 pp_antarctic_avg_ann_sea_ice: - extract_time: - start_day: 1 - start_month: 1 - start_year: 1979 - end_day: 31 - end_month: 12 - end_year: 2014 annual_statistics: operator: mean keep_group_coordinates: true @@ -108,13 +80,6 @@ preprocessors: convert_units: units: 1e6 km2 pp_avg_ann_global_temp: - extract_time: - start_day: 1 - start_month: 1 - start_year: 1979 - end_day: 31 - end_month: 12 - end_year: 2014 area_statistics: operator: mean annual_statistics: @@ -128,7 +93,7 @@ diagnostics: siconc: preprocessor: pp_arctic_sept_sea_ice mip: seaIce - additional_datasets: &id001 + additional_datasets: - project: CMIP7 activity: CMIP branding_suffix: tavg-u-hxy-u @@ -165,7 +130,7 @@ diagnostics: tas: preprocessor: pp_avg_ann_global_temp mip: atmos - additional_datasets: &id002 + additional_datasets: - project: CMIP7 activity: CMIP branding_suffix: tavg-h2m-hxy-u @@ -203,27 +168,13 @@ diagnostics: sea_ice_sensitivity_script: script: seaice/seaice_sensitivity.py observations: - observation period: 1979-2014 - sea ice sensitivity (Notz-style plot): + observation_period: + start_year: 1979 + end_year: 2014 + sea_ice_sensitivity: mean: -4.01 - standard deviation: 0.32 - plausible range: 1.28 - annual trends (Roach-style plot): - first point: - GMST trend: null - SIA trend: null - Pearson CC of SIA over GMST: null - significance of SIA over GMST: null - second point: - GMST trend: null - SIA trend: null - Pearson CC of SIA over GMST: null - significance of SIA over GMST: null - third point: - GMST trend: null - SIA trend: null - Pearson CC of SIA over GMST: null - significance of SIA over GMST: null + standard_deviation: 0.32 + plausible_range: 1.28 antarctic: description: Plots annual mean sea ice sensitivity below 0 latitude in millions of square kilometres @@ -231,33 +182,77 @@ diagnostics: siconc: preprocessor: pp_antarctic_avg_ann_sea_ice mip: seaIce - additional_datasets: *id001 + additional_datasets: + - project: CMIP7 + activity: CMIP + branding_suffix: tavg-u-hxy-u + dataset: ACCESS-ESM1-5 + ensemble: r1i1p1f1 + exp: historical + frequency: mon + grid: gn + institute: CSIRO + region: glb + timerange: 1979/2014 + - project: CMIP7 + activity: CMIP + branding_suffix: tavg-u-hxy-u + dataset: MPI-ESM1-2-LR + ensemble: r1i1p1f1 + exp: historical + frequency: mon + grid: gn + institute: MPI-M + region: glb + timerange: 1979/2014 + - project: CMIP7 + activity: CMIP + branding_suffix: tavg-u-hxy-u + dataset: CESM2 + ensemble: r1i1p1f1 + exp: historical + frequency: mon + grid: gn + institute: NCAR + region: glb + timerange: 1979/2014 tas: preprocessor: pp_avg_ann_global_temp mip: atmos - additional_datasets: *id002 + additional_datasets: + - project: CMIP7 + activity: CMIP + branding_suffix: tavg-h2m-hxy-u + dataset: ACCESS-ESM1-5 + ensemble: r1i1p1f1 + exp: historical + frequency: mon + grid: gn + institute: CSIRO + region: glb + timerange: 1979/2014 + - project: CMIP7 + activity: CMIP + branding_suffix: tavg-h2m-hxy-u + dataset: MPI-ESM1-2-LR + ensemble: r1i1p1f1 + exp: historical + frequency: mon + grid: gn + institute: MPI-M + region: glb + timerange: 1979/2014 + - project: CMIP7 + activity: CMIP + branding_suffix: tavg-h2m-hxy-u + dataset: CESM2 + ensemble: r1i1p1f1 + exp: historical + frequency: mon + grid: gn + institute: NCAR + region: glb + timerange: 1979/2014 scripts: sea_ice_sensitivity_script: script: seaice/seaice_sensitivity.py - observations: - observation period: null - sea ice sensitivity (Notz-style plot): - mean: null - standard deviation: null - plausible range: null - annual trends (Roach-style plot): - first point: - GMST trend: null - SIA trend: null - Pearson CC of SIA over GMST: null - significance of SIA over GMST: null - second point: - GMST trend: null - SIA trend: null - Pearson CC of SIA over GMST: null - significance of SIA over GMST: null - third point: - GMST trend: null - SIA trend: null - Pearson CC of SIA over GMST: null - significance of SIA over GMST: null diff --git a/packages/climate-ref-example/src/climate_ref_example/surface_temperature.py b/packages/climate-ref-example/src/climate_ref_example/surface_temperature.py index d73ad4607..d3e202608 100644 --- a/packages/climate-ref-example/src/climate_ref_example/surface_temperature.py +++ b/packages/climate-ref-example/src/climate_ref_example/surface_temperature.py @@ -390,7 +390,7 @@ class GlobalMeanSurfaceTemperatureBias(Diagnostic): RegistryRequest( slug="surface-temperature-obs", registry_name="obs4ref", - source_type="obs4MIPs", + source_type="obs4REF", facets={"source_id": _REFERENCE_SOURCE_ID, "variable_id": _REFERENCE_VARIABLE}, ), CMIP6Request( @@ -423,7 +423,7 @@ class GlobalMeanSurfaceTemperatureBias(Diagnostic): RegistryRequest( slug="surface-temperature-obs-cmip7", registry_name="obs4ref", - source_type="obs4MIPs", + source_type="obs4REF", facets={"source_id": _REFERENCE_SOURCE_ID, "variable_id": _REFERENCE_VARIABLE}, ), CMIP7Request( diff --git a/packages/climate-ref-example/tests/test-data/global-sst-bias/cmip7/catalog.yaml b/packages/climate-ref-example/tests/test-data/global-sst-bias/cmip7/catalog.yaml index 939f13a59..c82f7fe2d 100644 --- a/packages/climate-ref-example/tests/test-data/global-sst-bias/cmip7/catalog.yaml +++ b/packages/climate-ref-example/tests/test-data/global-sst-bias/cmip7/catalog.yaml @@ -88,14 +88,14 @@ obs4mips: source_id: HadISST-1-1 variable_id: ts datasets: - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2025-01-16 12:00:00' filename: ts_mon_HadISST-1-1_PCMDI_gn_187001-202501.nc finalised: true frequency: mon grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 + instance_id: obs4REF.obs4REF.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 institution_id: MOHC long_name: Surface Temperature nominal_resolution: 250 km diff --git a/packages/climate-ref-example/tests/test-data/global-sst-bias/default/catalog.yaml b/packages/climate-ref-example/tests/test-data/global-sst-bias/default/catalog.yaml index 0980d0297..4acdf8d51 100644 --- a/packages/climate-ref-example/tests/test-data/global-sst-bias/default/catalog.yaml +++ b/packages/climate-ref-example/tests/test-data/global-sst-bias/default/catalog.yaml @@ -92,14 +92,14 @@ obs4mips: source_id: HadISST-1-1 variable_id: ts datasets: - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2025-01-16 12:00:00' filename: ts_mon_HadISST-1-1_PCMDI_gn_187001-202501.nc finalised: true frequency: mon grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 + instance_id: obs4REF.obs4REF.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 institution_id: MOHC long_name: Surface Temperature nominal_resolution: 250 km diff --git a/packages/climate-ref-ilamb/src/climate_ref_ilamb/standard.py b/packages/climate-ref-ilamb/src/climate_ref_ilamb/standard.py index 921dd9051..d6c16b8e4 100644 --- a/packages/climate-ref-ilamb/src/climate_ref_ilamb/standard.py +++ b/packages/climate-ref-ilamb/src/climate_ref_ilamb/standard.py @@ -690,7 +690,7 @@ def _build_test_data_spec( # noqa: PLR0913 slug=slug, registry_name="obs4ref", facets=obs_filters, - source_type="obs4MIPs", + source_type="obs4REF", ), ) elif obs_source == "obs4mips": @@ -947,12 +947,11 @@ def __init__( # noqa: PLR0915, PLR0912 is_land=is_land, ) - # obs4MIPs data requirement, normally ilamb3 expects the `sources` to + # Observational data requirement, normally ilamb3 expects the `sources` to # resolve to keys in one of its data registries. If instead we find a # dictionary, then assume that these keys are meant to be keywords in a # REF data requirement. - # obs_source key is used to determine whether to fetch from ESGF - # or use the pre-fetched obs4REF registry. + # obs_source names where the test data is fetched from, the registry or ESGF. filters: dict[str, tuple[str, ...]] = {} obs_source = None for _, source in sources.items(): @@ -1030,7 +1029,7 @@ def execute(self, definition: ExecutionDefinition) -> None: # data not yet available in obs4{MIPs,REF}. This logic allows for # DataRequirement filters to be added as a 'source' in the ilamb # configure file. If a dictionary instead of a string was found, we - # populate an obs4MIPs requirement. + # populate an observational requirement. if SourceDatasetType.obs4MIPs in definition.datasets: # ilamb3 will expect the reference dataset dataframe to have a `key` # column that uniquely describes each dataset. Create one using the diff --git a/packages/climate-ref-ilamb/tests/test-data/burntfractionall-gfed/cmip6/catalog.yaml b/packages/climate-ref-ilamb/tests/test-data/burntfractionall-gfed/cmip6/catalog.yaml index 5ec81644a..5e3748ce6 100644 --- a/packages/climate-ref-ilamb/tests/test-data/burntfractionall-gfed/cmip6/catalog.yaml +++ b/packages/climate-ref-ilamb/tests/test-data/burntfractionall-gfed/cmip6/catalog.yaml @@ -134,14 +134,14 @@ obs4mips: variable_id: burntFractionAll version: v20260128 datasets: - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2020-12-16 12:00:00' filename: burntFractionAll_mon_GFED-5-0_REF_gr_199701-202012.nc finalised: true frequency: mon grid: 0.25x0.25 degree latitude x longitude grid_label: gr - instance_id: obs4MIPs.obs4MIPs.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 + instance_id: obs4REF.obs4REF.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 institution_id: NASA-NOSR long_name: Percentage of Entire Grid Cell That Is Covered by Burnt Vegetation (All Classes) diff --git a/packages/climate-ref-ilamb/tests/test-data/burntfractionall-gfed/cmip7/catalog.yaml b/packages/climate-ref-ilamb/tests/test-data/burntfractionall-gfed/cmip7/catalog.yaml index a807468b0..daf41fc7b 100644 --- a/packages/climate-ref-ilamb/tests/test-data/burntfractionall-gfed/cmip7/catalog.yaml +++ b/packages/climate-ref-ilamb/tests/test-data/burntfractionall-gfed/cmip7/catalog.yaml @@ -128,14 +128,14 @@ obs4mips: variable_id: burntFractionAll version: v20260128 datasets: - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2020-12-16 12:00:00' filename: burntFractionAll_mon_GFED-5-0_REF_gr_199701-202012.nc finalised: true frequency: mon grid: 0.25x0.25 degree latitude x longitude grid_label: gr - instance_id: obs4MIPs.obs4MIPs.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 + instance_id: obs4REF.obs4REF.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 institution_id: NASA-NOSR long_name: Percentage of Entire Grid Cell That Is Covered by Burnt Vegetation (All Classes) diff --git a/packages/climate-ref-ilamb/tests/test-data/csoil-hwsd2/cmip6/catalog.yaml b/packages/climate-ref-ilamb/tests/test-data/csoil-hwsd2/cmip6/catalog.yaml index 809a63bd9..234c8d690 100644 --- a/packages/climate-ref-ilamb/tests/test-data/csoil-hwsd2/cmip6/catalog.yaml +++ b/packages/climate-ref-ilamb/tests/test-data/csoil-hwsd2/cmip6/catalog.yaml @@ -143,7 +143,7 @@ obs4mips: frequency: fx grid: 0.5x0.5 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + instance_id: obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 institution_id: IIASA-FAO long_name: Carbon Mass in Model Soil Pool nominal_resolution: 0.5x0.5 degree diff --git a/packages/climate-ref-ilamb/tests/test-data/csoil-hwsd2/cmip7/catalog.yaml b/packages/climate-ref-ilamb/tests/test-data/csoil-hwsd2/cmip7/catalog.yaml index 0c7b23cde..7baf0d875 100644 --- a/packages/climate-ref-ilamb/tests/test-data/csoil-hwsd2/cmip7/catalog.yaml +++ b/packages/climate-ref-ilamb/tests/test-data/csoil-hwsd2/cmip7/catalog.yaml @@ -134,7 +134,7 @@ obs4mips: frequency: fx grid: 0.5x0.5 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + instance_id: obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 institution_id: IIASA-FAO long_name: Carbon Mass in Model Soil Pool nominal_resolution: 0.5x0.5 degree diff --git a/packages/climate-ref-ilamb/tests/test-data/gpp-wecann/cmip6/catalog.yaml b/packages/climate-ref-ilamb/tests/test-data/gpp-wecann/cmip6/catalog.yaml index e9cf7c88a..ea13d37de 100644 --- a/packages/climate-ref-ilamb/tests/test-data/gpp-wecann/cmip6/catalog.yaml +++ b/packages/climate-ref-ilamb/tests/test-data/gpp-wecann/cmip6/catalog.yaml @@ -224,7 +224,7 @@ obs4mips: frequency: mon grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + instance_id: obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 institution_id: ColumbiaU long_name: Carbon Mass Flux out of Atmosphere due to Gross Primary Production on Land diff --git a/packages/climate-ref-ilamb/tests/test-data/gpp-wecann/cmip7/catalog.yaml b/packages/climate-ref-ilamb/tests/test-data/gpp-wecann/cmip7/catalog.yaml index 39dd0347a..383b26a95 100644 --- a/packages/climate-ref-ilamb/tests/test-data/gpp-wecann/cmip7/catalog.yaml +++ b/packages/climate-ref-ilamb/tests/test-data/gpp-wecann/cmip7/catalog.yaml @@ -209,7 +209,7 @@ obs4mips: frequency: mon grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + instance_id: obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 institution_id: ColumbiaU long_name: Carbon Mass Flux out of Atmosphere due to Gross Primary Production on Land diff --git a/packages/climate-ref-ilamb/tests/test-data/mrro-lora/cmip6/catalog.yaml b/packages/climate-ref-ilamb/tests/test-data/mrro-lora/cmip6/catalog.yaml index 9373f5355..ea31db393 100644 --- a/packages/climate-ref-ilamb/tests/test-data/mrro-lora/cmip6/catalog.yaml +++ b/packages/climate-ref-ilamb/tests/test-data/mrro-lora/cmip6/catalog.yaml @@ -143,7 +143,7 @@ obs4mips: frequency: mon grid: 0.5x0.5 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + instance_id: obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 institution_id: ARCCSS long_name: Total Runoff nominal_resolution: 50 km diff --git a/packages/climate-ref-ilamb/tests/test-data/mrro-lora/cmip7/catalog.yaml b/packages/climate-ref-ilamb/tests/test-data/mrro-lora/cmip7/catalog.yaml index b56652403..59ec7e816 100644 --- a/packages/climate-ref-ilamb/tests/test-data/mrro-lora/cmip7/catalog.yaml +++ b/packages/climate-ref-ilamb/tests/test-data/mrro-lora/cmip7/catalog.yaml @@ -134,7 +134,7 @@ obs4mips: frequency: mon grid: 0.5x0.5 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + instance_id: obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 institution_id: ARCCSS long_name: Total Runoff nominal_resolution: 50 km diff --git a/packages/climate-ref-ilamb/tests/test-data/nbp-hoffman/cmip6/catalog.yaml b/packages/climate-ref-ilamb/tests/test-data/nbp-hoffman/cmip6/catalog.yaml index 6a7078d56..bbff58cee 100644 --- a/packages/climate-ref-ilamb/tests/test-data/nbp-hoffman/cmip6/catalog.yaml +++ b/packages/climate-ref-ilamb/tests/test-data/nbp-hoffman/cmip6/catalog.yaml @@ -137,14 +137,14 @@ obs4mips: variable_id: nbp version: v20251117 datasets: - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2010-05-24 12:00:00' filename: nbp_yr_Hoffman-1-0_REF_gm_1850-2010.nc finalised: true frequency: yr grid: global mean data grid_label: gm - instance_id: obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + instance_id: obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 institution_id: UCI-ORNL long_name: Carbon Mass Flux out of Atmosphere Due to Net Biospheric Production on Land diff --git a/packages/climate-ref-ilamb/tests/test-data/nbp-hoffman/cmip7/catalog.yaml b/packages/climate-ref-ilamb/tests/test-data/nbp-hoffman/cmip7/catalog.yaml index fd13cfce1..21305cf19 100644 --- a/packages/climate-ref-ilamb/tests/test-data/nbp-hoffman/cmip7/catalog.yaml +++ b/packages/climate-ref-ilamb/tests/test-data/nbp-hoffman/cmip7/catalog.yaml @@ -128,14 +128,14 @@ obs4mips: variable_id: nbp version: v20251117 datasets: - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2010-05-24 12:00:00' filename: nbp_yr_Hoffman-1-0_REF_gm_1850-2010.nc finalised: true frequency: yr grid: global mean data grid_label: gm - instance_id: obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + instance_id: obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 institution_id: UCI-ORNL long_name: Carbon Mass Flux out of Atmosphere Due to Net Biospheric Production on Land diff --git a/packages/climate-ref-ilamb/tests/test-data/snc-esacci/cmip6/catalog.yaml b/packages/climate-ref-ilamb/tests/test-data/snc-esacci/cmip6/catalog.yaml index c85a7f672..ffe38e03c 100644 --- a/packages/climate-ref-ilamb/tests/test-data/snc-esacci/cmip6/catalog.yaml +++ b/packages/climate-ref-ilamb/tests/test-data/snc-esacci/cmip6/catalog.yaml @@ -143,7 +143,7 @@ obs4mips: frequency: mon grid: 0.5x0.5 degree grid_label: gn - instance_id: obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + instance_id: obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 institution_id: ESACCI long_name: Fractional Snow Cover nominal_resolution: 0.5x0.5 degree diff --git a/packages/climate-ref-ilamb/tests/test-data/snc-esacci/cmip7/catalog.yaml b/packages/climate-ref-ilamb/tests/test-data/snc-esacci/cmip7/catalog.yaml index 2b6155a6b..a610cf3a8 100644 --- a/packages/climate-ref-ilamb/tests/test-data/snc-esacci/cmip7/catalog.yaml +++ b/packages/climate-ref-ilamb/tests/test-data/snc-esacci/cmip7/catalog.yaml @@ -134,7 +134,7 @@ obs4mips: frequency: mon grid: 0.5x0.5 degree grid_label: gn - instance_id: obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + instance_id: obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 institution_id: ESACCI long_name: Fractional Snow Cover nominal_resolution: 0.5x0.5 degree diff --git a/packages/climate-ref-ilamb/tests/test-data/so-woa2023-surface/cmip6/catalog.yaml b/packages/climate-ref-ilamb/tests/test-data/so-woa2023-surface/cmip6/catalog.yaml index b0718866d..0e0127fa1 100644 --- a/packages/climate-ref-ilamb/tests/test-data/so-woa2023-surface/cmip6/catalog.yaml +++ b/packages/climate-ref-ilamb/tests/test-data/so-woa2023-surface/cmip6/catalog.yaml @@ -836,14 +836,14 @@ obs4mips: variable_id: so version: v20251024 datasets: - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '1988-12-15 00:00:00' filename: so_monC_WOA-23_REF_gn_200501-202212.nc finalised: true frequency: monC grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + instance_id: obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 institution_id: NOAA-NCEI-OCL long_name: Objectively analyzed mean fields for sea_water_practical_salinity at standard depth levels. diff --git a/packages/climate-ref-ilamb/tests/test-data/so-woa2023-surface/cmip7/catalog.yaml b/packages/climate-ref-ilamb/tests/test-data/so-woa2023-surface/cmip7/catalog.yaml index 361eb1ada..79fd75e28 100644 --- a/packages/climate-ref-ilamb/tests/test-data/so-woa2023-surface/cmip7/catalog.yaml +++ b/packages/climate-ref-ilamb/tests/test-data/so-woa2023-surface/cmip7/catalog.yaml @@ -756,14 +756,14 @@ obs4mips: variable_id: so version: v20251024 datasets: - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '1988-12-15 00:00:00' filename: so_monC_WOA-23_REF_gn_200501-202212.nc finalised: true frequency: monC grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + instance_id: obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 institution_id: NOAA-NCEI-OCL long_name: Objectively analyzed mean fields for sea_water_practical_salinity at standard depth levels. diff --git a/packages/climate-ref-ilamb/tests/test-data/thetao-woa2023-surface/cmip6/catalog.yaml b/packages/climate-ref-ilamb/tests/test-data/thetao-woa2023-surface/cmip6/catalog.yaml index ef4486cf4..a29ca2795 100644 --- a/packages/climate-ref-ilamb/tests/test-data/thetao-woa2023-surface/cmip6/catalog.yaml +++ b/packages/climate-ref-ilamb/tests/test-data/thetao-woa2023-surface/cmip6/catalog.yaml @@ -836,14 +836,14 @@ obs4mips: variable_id: thetao version: v20251024 datasets: - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '1988-12-15 00:00:00' filename: thetao_monC_WOA-23_REF_gn_200501-202212.nc finalised: true frequency: monC grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + instance_id: obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 institution_id: NOAA-NCEI-OCL long_name: Objectively analyzed mean fields for sea_water_temperature at standard depth levels. diff --git a/packages/climate-ref-ilamb/tests/test-data/thetao-woa2023-surface/cmip7/catalog.yaml b/packages/climate-ref-ilamb/tests/test-data/thetao-woa2023-surface/cmip7/catalog.yaml index 6233b4c1c..ed0e9062f 100644 --- a/packages/climate-ref-ilamb/tests/test-data/thetao-woa2023-surface/cmip7/catalog.yaml +++ b/packages/climate-ref-ilamb/tests/test-data/thetao-woa2023-surface/cmip7/catalog.yaml @@ -756,14 +756,14 @@ obs4mips: variable_id: thetao version: v20251024 datasets: - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '1988-12-15 00:00:00' filename: thetao_monC_WOA-23_REF_gn_200501-202212.nc finalised: true frequency: monC grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + instance_id: obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 institution_id: NOAA-NCEI-OCL long_name: Objectively analyzed mean fields for sea_water_temperature at standard depth levels. diff --git a/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_amoc_rapid_.yml b/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_amoc_rapid_.yml index 124066dd3..ebf013c75 100644 --- a/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_amoc_rapid_.yml +++ b/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_amoc_rapid_.yml @@ -4,173 +4,173 @@ cmip6_historical_gn_r1i1p101f1_GISS-E3-G__obs4mips_gm_RAPID-2023-1a_msftmz_v2025 - CMIP6.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.Ofx.sftof.gn.v20230320 - CMIP6.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.Omon.msftmz.gn.v20230320 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_gn_r1i1p1f1_ACCESS-CM2__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.CSIRO-ARCCSS.ACCESS-CM2.historical.r1i1p1f1.Ofx.areacello.gn.v20191108 - CMIP6.CMIP.CSIRO-ARCCSS.ACCESS-CM2.historical.r1i1p1f1.Ofx.sftof.gn.v20191108 - CMIP6.CMIP.CSIRO-ARCCSS.ACCESS-CM2.historical.r1i1p1f1.Omon.msftmz.gn.v20191108 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_gn_r1i1p1f1_ACCESS-ESM1-5__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Ofx.areacello.gn.v20191115 - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Ofx.sftof.gn.v20191115 - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Omon.msftmz.gn.v20191115 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_gn_r1i1p1f1_CAS-ESM2-0__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.CAS.CAS-ESM2-0.historical.r1i1p1f1.Ofx.areacello.gn.v20201228 - CMIP6.CMIP.CAS.CAS-ESM2-0.historical.r1i1p1f1.Ofx.volcello.gn.v20201228 - CMIP6.CMIP.CAS.CAS-ESM2-0.historical.r1i1p1f1.Omon.msftmz.gn.v20201229 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_gn_r1i1p1f1_CESM2-FV2__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.Ofx.areacello.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.Ofx.sftof.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.Omon.msftmz.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_gn_r1i1p1f1_CESM2-WACCM-FV2__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.Ofx.areacello.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.Ofx.sftof.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.Omon.msftmz.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_gn_r1i1p1f1_CESM2-WACCM__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.Ofx.sftof.gn.v20190227 - CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.Omon.msftmz.gn.v20190917 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_gn_r1i1p1f1_CESM2__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Ofx.areacello.gn.v20190308 - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Ofx.sftof.gn.v20190308 - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Omon.msftmz.gn.v20190919 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_gn_r1i1p1f1_CanESM5-1__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.Ofx.areacello.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.Ofx.volcello.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.Omon.msftmz.gn.v20190429 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_gn_r1i1p1f1_CanESM5__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.Ofx.areacello.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.Ofx.sftof.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.Omon.msftmz.gn.v20190429 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_gn_r1i1p1f1_FGOALS-g3__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.Ofx.areacello.gn.v20200917 - CMIP6.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.Ofx.volcello.gn.v20200917 - CMIP6.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.Omon.msftmz.gn.v20191012 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_gn_r1i1p1f1_GISS-E2-1-G-CC__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-1-G-CC.historical.r1i1p1f1.Omon.msftmz.gn.v20190815 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_gn_r1i1p1f1_GISS-E2-2-G__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-2-G.historical.r1i1p1f1.Omon.msftmz.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_gn_r1i1p1f1_ICON-ESM-LR__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.Ofx.areacello.gn.v20210215 - CMIP6.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.Omon.msftmz.gn.v20210215 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_gn_r1i1p1f1_MPI-ESM-1-2-HAM__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.Ofx.areacello.gn.v20190627 - CMIP6.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.Ofx.sftof.gn.v20190627 - CMIP6.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.Omon.msftmz.gn.v20190627 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_gn_r1i1p1f1_MPI-ESM1-2-HR__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.Ofx.areacello.gn.v20190710 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.Ofx.sftof.gn.v20190710 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.Omon.msftmz.gn.v20190710 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_gn_r1i1p1f1_MPI-ESM1-2-LR__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.Ofx.areacello.gn.v20190710 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.Ofx.sftof.gn.v20190710 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.Omon.msftmz.gn.v20190710 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_gn_r1i1p1f1_SAM0-UNICON__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.Ofx.areacello.gn.v20190323 - CMIP6.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.Omon.msftmz.gn.v20190323 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_gn_r1i1p2f1_CanESM5-CanOE__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.Ofx.areacello.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.Ofx.sftof.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.Omon.msftmz.gn.v20190429 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_gr1_r1i1p1f1_INM-CM4-8__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.INM.INM-CM4-8.historical.r1i1p1f1.Omon.msftmz.gr1.v20190530 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_gr1_r1i1p1f1_INM-CM5-0__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.INM.INM-CM5-0.historical.r1i1p1f1.Omon.msftmz.gr1.v20190610 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_gr2z_r1i1p1f1_MRI-ESM2-0__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.Omon.msftmz.gr2z.v20191210 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_gr_r1i1p1f1_E3SM-1-1-ECA__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.E3SM-Project.E3SM-1-1-ECA.historical.r1i1p1f1.Omon.msftmz.gr.v20200917 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_gr_r1i1p1f1_E3SM-1-1__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.E3SM-Project.E3SM-1-1.historical.r1i1p1f1.Omon.msftmz.gr.v20200917 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_gr_r1i1p1f1_MIROC6__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.MIROC.MIROC6.historical.r1i1p1f1.Omon.msftmz.gr.v20200421 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_gr_r1i1p1f2_MIROC-ES2L__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.Omon.msftmz.gr.v20210317 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_grz_r1i1p1f1_NorCPM1__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.NCC.NorCPM1.historical.r1i1p1f1.Omon.msftmz.grz.v20200724 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_grz_r1i1p1f1_NorESM2-MM__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.Omon.msftmz.grz.v20191108 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 cmip6_historical_grz_r1i1p4f1_NorESM2-LM__obs4mips_gm_RAPID-2023-1a_msftmz_v20250902: cmip6: - CMIP6.CMIP.NCC.NorESM2-LM.historical.r1i1p4f1.Omon.msftmz.grz.v20230616 obs4mips: - - obs4MIPs.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 + - obs4REF.obs4REF.NOC.RAPID-2023-1a.mon.msftmz.site.gm.v20250902 diff --git a/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_burntfractionall_gfed_.yml b/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_burntfractionall_gfed_.yml index 9b1fa95dc..5e568fb53 100644 --- a/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_burntfractionall_gfed_.yml +++ b/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_burntfractionall_gfed_.yml @@ -4,133 +4,133 @@ cmip6_historical_gn_r1i1p1f1_CESM2-FV2__obs4mips_gr_GFED-5-0_burntFractionAll_v2 - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.fx.areacella.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.fx.sftlf.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 + - obs4REF.obs4REF.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 cmip6_historical_gn_r1i1p1f1_CESM2-WACCM-FV2__obs4mips_gr_GFED-5-0_burntFractionAll_v20260128: cmip6: - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.Lmon.burntFractionAll.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.fx.areacella.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.fx.sftlf.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 + - obs4REF.obs4REF.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 cmip6_historical_gn_r1i1p1f1_CESM2-WACCM__obs4mips_gr_GFED-5-0_burntFractionAll_v20260128: cmip6: - CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.Lmon.burntFractionAll.gn.v20190227 - CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.fx.areacella.gn.v20190227 - CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.fx.sftlf.gn.v20190227 obs4mips: - - obs4MIPs.obs4MIPs.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 + - obs4REF.obs4REF.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 cmip6_historical_gn_r1i1p1f1_CESM2__obs4mips_gr_GFED-5-0_burntFractionAll_v20260128: cmip6: - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Lmon.burntFractionAll.gn.v20190308 - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.fx.areacella.gn.v20190308 - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.fx.sftlf.gn.v20190308 obs4mips: - - obs4MIPs.obs4MIPs.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 + - obs4REF.obs4REF.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 cmip6_historical_gn_r1i1p1f1_CMCC-CM2-SR5__obs4mips_gr_GFED-5-0_burntFractionAll_v20260128: cmip6: - CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.Lmon.burntFractionAll.gn.v20200616 - CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.fx.areacella.gn.v20200616 - CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.fx.sftlf.gn.v20200616 obs4mips: - - obs4MIPs.obs4MIPs.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 + - obs4REF.obs4REF.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 cmip6_historical_gn_r1i1p1f1_CMCC-ESM2__obs4mips_gr_GFED-5-0_burntFractionAll_v20260128: cmip6: - CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.Lmon.burntFractionAll.gn.v20210114 - CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.fx.areacella.gn.v20210114 - CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.fx.sftlf.gn.v20210114 obs4mips: - - obs4MIPs.obs4MIPs.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 + - obs4REF.obs4REF.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 cmip6_historical_gn_r1i1p1f1_NorESM2-LM__obs4mips_gr_GFED-5-0_burntFractionAll_v20260128: cmip6: - CMIP6.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.Lmon.burntFractionAll.gn.v20210818 - CMIP6.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.fx.areacella.gn.v20190815 - CMIP6.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.fx.sftlf.gn.v20191108 obs4mips: - - obs4MIPs.obs4MIPs.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 + - obs4REF.obs4REF.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 cmip6_historical_gn_r1i1p1f1_NorESM2-MM__obs4mips_gr_GFED-5-0_burntFractionAll_v20260128: cmip6: - CMIP6.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.Lmon.burntFractionAll.gn.v20210818 - CMIP6.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.fx.areacella.gn.v20191108 - CMIP6.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.fx.sftlf.gn.v20191108 obs4mips: - - obs4MIPs.obs4MIPs.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 + - obs4REF.obs4REF.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 cmip6_historical_gr_r1i1p1f1_EC-Earth3-CC__obs4mips_gr_GFED-5-0_burntFractionAll_v20260128: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.Lmon.burntFractionAll.gr.v20210113 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.fx.areacella.gr.v20210616 obs4mips: - - obs4MIPs.obs4MIPs.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 + - obs4REF.obs4REF.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 cmip6_historical_gr_r1i1p1f2_CNRM-ESM2-1__obs4mips_gr_GFED-5-0_burntFractionAll_v20260128: cmip6: - CMIP6.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r13i1p1f2.fx.areacella.gr.v20250328 - CMIP6.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.Lmon.burntFractionAll.gr.v20181206 obs4mips: - - obs4MIPs.obs4MIPs.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 + - obs4REF.obs4REF.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 cmip7_historical_gn_CESM2-FV2_r1i1p1f1__obs4mips_gr_GFED-5-0_burntFractionAll_v20260128: cmip7: - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.mon.burntFractionAll.tavg-u-hxy-u.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 + - obs4REF.obs4REF.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 cmip7_historical_gn_CESM2-WACCM-FV2_r1i1p1f1__obs4mips_gr_GFED-5-0_burntFractionAll_v20260128: cmip7: - CMIP7.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.glb.mon.burntFractionAll.tavg-u-hxy-u.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 + - obs4REF.obs4REF.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 cmip7_historical_gn_CESM2-WACCM_r1i1p1f1__obs4mips_gr_GFED-5-0_burntFractionAll_v20260128: cmip7: - CMIP7.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190227 - CMIP7.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190227 - CMIP7.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.glb.mon.burntFractionAll.tavg-u-hxy-u.gn.v20190227 obs4mips: - - obs4MIPs.obs4MIPs.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 + - obs4REF.obs4REF.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 cmip7_historical_gn_CESM2_r1i1p1f1__obs4mips_gr_GFED-5-0_burntFractionAll_v20260128: cmip7: - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190308 - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190308 - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.mon.burntFractionAll.tavg-u-hxy-u.gn.v20190308 obs4mips: - - obs4MIPs.obs4MIPs.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 + - obs4REF.obs4REF.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 cmip7_historical_gn_CMCC-CM2-SR5_r1i1p1f1__obs4mips_gr_GFED-5-0_burntFractionAll_v20260128: cmip7: - CMIP7.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20200616 - CMIP7.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20200616 - CMIP7.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.glb.mon.burntFractionAll.tavg-u-hxy-u.gn.v20200616 obs4mips: - - obs4MIPs.obs4MIPs.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 + - obs4REF.obs4REF.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 cmip7_historical_gn_CMCC-ESM2_r1i1p1f1__obs4mips_gr_GFED-5-0_burntFractionAll_v20260128: cmip7: - CMIP7.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20210114 - CMIP7.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20210114 - CMIP7.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.glb.mon.burntFractionAll.tavg-u-hxy-u.gn.v20210114 obs4mips: - - obs4MIPs.obs4MIPs.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 + - obs4REF.obs4REF.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 cmip7_historical_gn_NorESM2-LM_r1i1p1f1__obs4mips_gr_GFED-5-0_burntFractionAll_v20260128: cmip7: - CMIP7.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190815 - CMIP7.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20191108 - CMIP7.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.glb.mon.burntFractionAll.tavg-u-hxy-u.gn.v20210818 obs4mips: - - obs4MIPs.obs4MIPs.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 + - obs4REF.obs4REF.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 cmip7_historical_gn_NorESM2-MM_r1i1p1f1__obs4mips_gr_GFED-5-0_burntFractionAll_v20260128: cmip7: - CMIP7.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20191108 - CMIP7.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20191108 - CMIP7.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.glb.mon.burntFractionAll.tavg-u-hxy-u.gn.v20210818 obs4mips: - - obs4MIPs.obs4MIPs.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 + - obs4REF.obs4REF.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 cmip7_historical_gr_CNRM-ESM2-1_r1i1p1f2__obs4mips_gr_GFED-5-0_burntFractionAll_v20260128: cmip7: - CMIP7.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r13i1p1f2.glb.fx.areacella.ti-u-hxy-u.gr.v20250328 - CMIP7.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.glb.mon.burntFractionAll.tavg-u-hxy-u.gr.v20181206 obs4mips: - - obs4MIPs.obs4MIPs.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 + - obs4REF.obs4REF.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 cmip7_historical_gr_EC-Earth3-CC_r1i1p1f1__obs4mips_gr_GFED-5-0_burntFractionAll_v20260128: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20210616 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.glb.mon.burntFractionAll.tavg-u-hxy-u.gr.v20210113 obs4mips: - - obs4MIPs.obs4MIPs.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 + - obs4REF.obs4REF.NASA-NOSR.GFED-5-0.mon.burntFractionAll.25km.gr.v20260128 diff --git a/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_csoil_hwsd2_.yml b/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_csoil_hwsd2_.yml index c07e5375a..990c3caf7 100644 --- a/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_csoil_hwsd2_.yml +++ b/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_csoil_hwsd2_.yml @@ -4,447 +4,447 @@ cmip6_historical_gn_r1i1p1f1_ACCESS-ESM1-5__obs4mips_gn_HWSD-2-0_cSoil_v20250903 - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.fx.areacella.gn.v20191115 - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.fx.sftlf.gn.v20191115 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gn_r1i1p1f1_AWI-ESM-1-1-LR__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.Emon.cSoil.gn.v20200212 - CMIP6.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.fx.areacella.gn.v20200212 - CMIP6.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.fx.sftlf.gn.v20200909 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gn_r1i1p1f1_BCC-CSM2-MR__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.BCC.BCC-CSM2-MR.historical.r1i1p1f1.Emon.cSoil.gn.v20181114 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gn_r1i1p1f1_BCC-ESM1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.BCC.BCC-ESM1.1pctCO2.r1i1p1f1.fx.areacella.gn.v20190613 - CMIP6.CMIP.BCC.BCC-ESM1.historical.r1i1p1f1.Emon.cSoil.gn.v20181114 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gn_r1i1p1f1_CESM2-FV2__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.Emon.cSoil.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.fx.areacella.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.fx.sftlf.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gn_r1i1p1f1_CESM2-WACCM-FV2__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.Emon.cSoil.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.fx.areacella.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.fx.sftlf.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gn_r1i1p1f1_CESM2-WACCM__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.Emon.cSoil.gn.v20190227 - CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.fx.areacella.gn.v20190227 - CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.fx.sftlf.gn.v20190227 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gn_r1i1p1f1_CESM2__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Emon.cSoil.gn.v20190308 - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.fx.areacella.gn.v20190308 - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.fx.sftlf.gn.v20190308 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gn_r1i1p1f1_CMCC-CM2-SR5__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.Emon.cSoil.gn.v20200616 - CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.fx.areacella.gn.v20200616 - CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.fx.sftlf.gn.v20200616 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gn_r1i1p1f1_CMCC-ESM2__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.Emon.cSoil.gn.v20210114 - CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.fx.areacella.gn.v20210114 - CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.fx.sftlf.gn.v20210114 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gn_r1i1p1f1_CanESM5-1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.Emon.cSoil.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.fx.areacella.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.fx.sftlf.gn.v20190429 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gn_r1i1p1f1_CanESM5__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.Emon.cSoil.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.fx.areacella.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.fx.sftlf.gn.v20190429 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gn_r1i1p1f1_GISS-E2-1-G-CC__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-1-G-CC.historical.r1i1p1f1.Emon.cSoil.gn.v20190815 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gn_r1i1p1f1_GISS-E2-1-G__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-1-G.historical.r1i1p1f1.Emon.cSoil.gn.v20181015 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gn_r1i1p1f1_GISS-E2-1-H__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-1-H.historical.r1i1p1f1.Emon.cSoil.gn.v20190403 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gn_r1i1p1f1_MPI-ESM-1-2-HAM__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.Emon.cSoil.gn.v20190627 - CMIP6.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.fx.areacella.gn.v20190627 - CMIP6.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.fx.sftlf.gn.v20190627 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gn_r1i1p1f1_MPI-ESM1-2-LR__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.Emon.cSoil.gn.v20190710 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.fx.areacella.gn.v20190710 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.fx.sftlf.gn.v20190710 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gn_r1i1p1f1_NorCPM1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.NCC.NorCPM1.historical.r1i1p1f1.Emon.cSoil.gn.v20200724 - CMIP6.CMIP.NCC.NorCPM1.historical.r1i1p1f1.fx.areacella.gn.v20200724 - CMIP6.CMIP.NCC.NorCPM1.historical.r1i1p1f1.fx.sftlf.gn.v20200724 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gn_r1i1p1f1_NorESM2-LM__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.C4MIP CDRMIP.NCC.NorESM2-LM.esm-1pct-brch-1000PgC.r1i1p1f1.fx.areacella.gn.v20191108 - CMIP6.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.Emon.cSoil.gn.v20191108 - CMIP6.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.fx.sftlf.gn.v20191108 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gn_r1i1p1f1_NorESM2-MM__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.Emon.cSoil.gn.v20191108 - CMIP6.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.fx.areacella.gn.v20191108 - CMIP6.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.fx.sftlf.gn.v20191108 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gn_r1i1p1f1_SAM0-UNICON__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.Emon.cSoil.gn.v20190323 - CMIP6.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.fx.areacella.gn.v20190323 - CMIP6.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.fx.sftlf.gn.v20190323 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gn_r1i1p1f1_TaiESM1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.Emon.cSoil.gn.v20200624 - CMIP6.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.fx.areacella.gn.v20200624 - CMIP6.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.fx.sftlf.gn.v20200624 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gn_r1i1p1f2_MIROC-ES2L__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.Emon.cSoil.gn.v20200124 - CMIP6.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.fx.areacella.gn.v20190823 - CMIP6.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.fx.sftlf.gn.v20190823 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gn_r1i1p1f2_UKESM1-0-LL__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.MOHC.UKESM1-0-LL.historical.r1i1p1f2.Emon.cSoil.gn.v20190627 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gn_r1i1p1f2_UKESM1-1-LL__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.MOHC.UKESM1-1-LL.historical.r1i1p1f2.Emon.cSoil.gn.v20220512 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gr1_r1i1p1f1_GFDL-ESM4__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.Emon.cSoil.gr1.v20190726 - CMIP6.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.fx.areacella.gr1.v20190726 - CMIP6.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.fx.sftlf.gr1.v20190726 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gr1_r1i1p1f1_KIOST-ESM__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.KIOST.KIOST-ESM.historical.r1i1p1f1.Emon.cSoil.gr1.v20210601 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gr_r1i1p101f1_GISS-E3-G__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.Emon.cSoil.gr.v20230320 - CMIP6.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.fx.areacella.gr.v20230320 - CMIP6.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.fx.sftlf.gr.v20230320 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gr_r1i1p1f1_EC-Earth3-CC__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.Emon.cSoil.gr.v20210113 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.fx.areacella.gr.v20210616 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gr_r1i1p1f1_EC-Earth3-Veg-LR__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.Emon.cSoil.gr.v20201116 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.fx.areacella.gr.v20200217 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.fx.sftlf.gr.v20200217 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gr_r1i1p1f1_EC-Earth3-Veg__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r11i1p1f1.fx.areacella.gr.v20230203 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.Emon.cSoil.gr.v20211207 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.fx.sftlf.gr.v20211207 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gr_r1i1p1f1_IPSL-CM5A2-INCA__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.IPSL.IPSL-CM5A2-INCA.historical.r1i1p1f1.Emon.cSoil.gr.v20200729 - CMIP6.CMIP.IPSL.IPSL-CM5A2-INCA.historical.r1i1p1f1.fx.areacella.gr.v20200729 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gr_r1i1p1f1_IPSL-CM6A-LR-INCA__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.IPSL.IPSL-CM6A-LR-INCA.historical.r1i1p1f1.Emon.cSoil.gr.v20210216 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gr_r1i1p1f1_IPSL-CM6A-LR__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.Emon.cSoil.gr.v20180803 - CMIP6.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.fx.areacella.gr.v20180803 - CMIP6.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.fx.sftlf.gr.v20180803 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip6_historical_gr_r1i1p1f2_CNRM-ESM2-1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip6: - CMIP6.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r13i1p1f2.fx.areacella.gr.v20250328 - CMIP6.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.Emon.cSoil.gr.v20181206 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gn_ACCESS-ESM1-5_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20191115 - CMIP7.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20191115 - CMIP7.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gn.v20191115 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gn_AWI-ESM-1-1-LR_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20200212 - CMIP7.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20200909 - CMIP7.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gn.v20200212 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gn_BCC-CSM2-MR_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.BCC.BCC-CSM2-MR.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gn.v20181114 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gn_BCC-ESM1_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.BCC.BCC-ESM1.1pctCO2.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190613 - CMIP7.CMIP.BCC.BCC-ESM1.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gn.v20181114 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gn_CESM2-FV2_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gn_CESM2-WACCM-FV2_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gn_CESM2-WACCM_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190227 - CMIP7.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190227 - CMIP7.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gn.v20190227 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gn_CESM2_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190308 - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190308 - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gn.v20190308 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gn_CMCC-CM2-SR5_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20200616 - CMIP7.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20200616 - CMIP7.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gn.v20200616 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gn_CMCC-ESM2_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20210114 - CMIP7.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20210114 - CMIP7.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gn.v20210114 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gn_CanESM5-1_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gn.v20190429 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gn_CanESM5_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.CCCma.CanESM5.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gn.v20190429 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gn_GISS-E2-1-G-CC_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-1-G-CC.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gn.v20190815 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gn_GISS-E2-1-G_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-1-G.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gn.v20181015 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gn_GISS-E2-1-H_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-1-H.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gn.v20190403 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gn_MIROC-ES2L_r1i1p1f2__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.glb.fx.areacella.ti-u-hxy-u.gn.v20190823 - CMIP7.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.glb.fx.sftlf.ti-u-hxy-u.gn.v20190823 - CMIP7.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.glb.mon.cSoil.tavg-u-hxy-lnd.gn.v20200124 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gn_MPI-ESM-1-2-HAM_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190627 - CMIP7.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190627 - CMIP7.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gn.v20190627 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gn_MPI-ESM1-2-LR_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190710 - CMIP7.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190710 - CMIP7.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gn.v20190710 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gn_NorCPM1_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.NCC.NorCPM1.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20200724 - CMIP7.CMIP.NCC.NorCPM1.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20200724 - CMIP7.CMIP.NCC.NorCPM1.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gn.v20200724 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gn_NorESM2-LM_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190815 - CMIP7.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20191108 - CMIP7.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gn.v20191108 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gn_NorESM2-MM_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20191108 - CMIP7.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20191108 - CMIP7.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gn.v20191108 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gn_SAM0-UNICON_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190323 - CMIP7.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190323 - CMIP7.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gn.v20190323 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gn_TaiESM1_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20200624 - CMIP7.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20200624 - CMIP7.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gn.v20200624 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gn_UKESM1-0-LL_r1i1p1f2__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.MOHC.UKESM1-0-LL.historical.r1i1p1f2.glb.mon.cSoil.tavg-u-hxy-lnd.gn.v20190627 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gn_UKESM1-1-LL_r1i1p1f2__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.MOHC.UKESM1-1-LL.historical.r1i1p1f2.glb.mon.cSoil.tavg-u-hxy-lnd.gn.v20220512 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gr1_GFDL-ESM4_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr1.v20190726 - CMIP7.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr1.v20190726 - CMIP7.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gr1.v20190726 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gr1_KIOST-ESM_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.KIOST.KIOST-ESM.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gr1.v20210601 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gr_CNRM-ESM2-1_r1i1p1f2__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r13i1p1f2.glb.fx.areacella.ti-u-hxy-u.gr.v20250328 - CMIP7.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.glb.mon.cSoil.tavg-u-hxy-lnd.gr.v20181206 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gr_EC-Earth3-CC_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20210616 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gr.v20210113 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gr_EC-Earth3-Veg-LR_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20200217 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20200217 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gr.v20201116 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gr_EC-Earth3-Veg_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r11i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20230203 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20211207 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gr.v20211207 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gr_GISS-E3-G_r1i1p101f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.glb.fx.areacella.ti-u-hxy-u.gr.v20230320 - CMIP7.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20230320 - CMIP7.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.glb.mon.cSoil.tavg-u-hxy-lnd.gr.v20230320 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gr_IPSL-CM5A2-INCA_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.IPSL.IPSL-CM5A2-INCA.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20200729 - CMIP7.CMIP.IPSL.IPSL-CM5A2-INCA.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gr.v20200729 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gr_IPSL-CM6A-LR-INCA_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.IPSL.IPSL-CM6A-LR-INCA.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gr.v20210216 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 cmip7_historical_gr_IPSL-CM6A-LR_r1i1p1f1__obs4mips_gn_HWSD-2-0_cSoil_v20250903: cmip7: - CMIP7.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20180803 - CMIP7.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20180803 - CMIP7.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.glb.mon.cSoil.tavg-u-hxy-lnd.gr.v20180803 obs4mips: - - obs4MIPs.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 + - obs4REF.obs4REF.IIASA-FAO.HWSD-2-0.fx.cSoil.0.5x0.5degree.gn.v20250903 diff --git a/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_gpp_wecann_.yml b/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_gpp_wecann_.yml index c16ae15d6..6cfd4e834 100644 --- a/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_gpp_wecann_.yml +++ b/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_gpp_wecann_.yml @@ -6,7 +6,7 @@ cmip6_historical_gn_r1i1p1f1_ACCESS-ESM1-5__obs4mips_gn_WECANN-1-0_gpp_v20250902 - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.fx.areacella.gn.v20191115 - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.fx.sftlf.gn.v20191115 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_AWI-ESM-1-1-LR__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.Amon.pr.gn.v20200212 @@ -15,14 +15,14 @@ cmip6_historical_gn_r1i1p1f1_AWI-ESM-1-1-LR__obs4mips_gn_WECANN-1-0_gpp_v2025090 - CMIP6.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.fx.areacella.gn.v20200212 - CMIP6.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.fx.sftlf.gn.v20200909 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_BCC-CSM2-MR__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.BCC.BCC-CSM2-MR.historical.r1i1p1f1.Amon.pr.gn.v20181126 - CMIP6.CMIP.BCC.BCC-CSM2-MR.historical.r1i1p1f1.Amon.tas.gn.v20181126 - CMIP6.CMIP.BCC.BCC-CSM2-MR.historical.r1i1p1f1.Lmon.gpp.gn.v20181114 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_BCC-ESM1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.BCC.BCC-ESM1.1pctCO2.r1i1p1f1.fx.areacella.gn.v20190613 @@ -30,14 +30,14 @@ cmip6_historical_gn_r1i1p1f1_BCC-ESM1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP6.CMIP.BCC.BCC-ESM1.historical.r1i1p1f1.Amon.tas.gn.v20181214 - CMIP6.CMIP.BCC.BCC-ESM1.historical.r1i1p1f1.Lmon.gpp.gn.v20181114 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_CAS-ESM2-0__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.CAS.CAS-ESM2-0.historical.r1i1p1f1.Amon.pr.gn.v20201227 - CMIP6.CMIP.CAS.CAS-ESM2-0.historical.r1i1p1f1.Amon.tas.gn.v20201227 - CMIP6.CMIP.CAS.CAS-ESM2-0.historical.r1i1p1f1.Lmon.gpp.gn.v20201224 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_CESM2-FV2__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.Amon.pr.gn.v20191120 @@ -46,7 +46,7 @@ cmip6_historical_gn_r1i1p1f1_CESM2-FV2__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.fx.areacella.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.fx.sftlf.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_CESM2-WACCM__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.Amon.pr.gn.v20190415 @@ -55,7 +55,7 @@ cmip6_historical_gn_r1i1p1f1_CESM2-WACCM__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.fx.areacella.gn.v20190227 - CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.fx.sftlf.gn.v20190227 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_CESM2__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Amon.pr.gn.v20190401 @@ -64,7 +64,7 @@ cmip6_historical_gn_r1i1p1f1_CESM2__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.fx.areacella.gn.v20190308 - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.fx.sftlf.gn.v20190308 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_CMCC-CM2-SR5__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.Amon.pr.gn.v20200616 @@ -73,7 +73,7 @@ cmip6_historical_gn_r1i1p1f1_CMCC-CM2-SR5__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.fx.areacella.gn.v20200616 - CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.fx.sftlf.gn.v20200616 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_CMCC-ESM2__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.Amon.pr.gn.v20210114 @@ -82,7 +82,7 @@ cmip6_historical_gn_r1i1p1f1_CMCC-ESM2__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.fx.areacella.gn.v20210114 - CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.fx.sftlf.gn.v20210114 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_CanESM5-1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.Amon.pr.gn.v20190429 @@ -91,7 +91,7 @@ cmip6_historical_gn_r1i1p1f1_CanESM5-1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP6.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.fx.areacella.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.fx.sftlf.gn.v20190429 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_CanESM5__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.Amon.pr.gn.v20190429 @@ -100,42 +100,42 @@ cmip6_historical_gn_r1i1p1f1_CanESM5__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.fx.areacella.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.fx.sftlf.gn.v20190429 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_GISS-E2-1-G-CC__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-1-G-CC.historical.r1i1p1f1.Amon.pr.gn.v20190815 - CMIP6.CMIP.NASA-GISS.GISS-E2-1-G-CC.historical.r1i1p1f1.Amon.tas.gn.v20190815 - CMIP6.CMIP.NASA-GISS.GISS-E2-1-G-CC.historical.r1i1p1f1.Lmon.gpp.gn.v20190815 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_GISS-E2-1-G__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-1-G.historical.r1i1p1f1.Amon.pr.gn.v20180827 - CMIP6.CMIP.NASA-GISS.GISS-E2-1-G.historical.r1i1p1f1.Amon.tas.gn.v20180827 - CMIP6.CMIP.NASA-GISS.GISS-E2-1-G.historical.r1i1p1f1.Lmon.gpp.gn.v20181015 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_GISS-E2-1-H__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-1-H.historical.r1i1p1f1.Amon.pr.gn.v20190403 - CMIP6.CMIP.NASA-GISS.GISS-E2-1-H.historical.r1i1p1f1.Amon.tas.gn.v20190403 - CMIP6.CMIP.NASA-GISS.GISS-E2-1-H.historical.r1i1p1f1.Lmon.gpp.gn.v20190403 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_GISS-E2-2-G__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-2-G.historical.r1i1p1f1.Amon.pr.gn.v20191120 - CMIP6.CMIP.NASA-GISS.GISS-E2-2-G.historical.r1i1p1f1.Amon.tas.gn.v20191120 - CMIP6.CMIP.NASA-GISS.GISS-E2-2-G.historical.r1i1p1f1.Lmon.gpp.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_GISS-E2-2-H__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-2-H.historical.r1i1p1f1.Amon.pr.gn.v20191120 - CMIP6.CMIP.NASA-GISS.GISS-E2-2-H.historical.r1i1p1f1.Amon.tas.gn.v20191120 - CMIP6.CMIP.NASA-GISS.GISS-E2-2-H.historical.r1i1p1f1.Lmon.gpp.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_ICON-ESM-LR__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.Amon.pr.gn.v20210215 @@ -144,7 +144,7 @@ cmip6_historical_gn_r1i1p1f1_ICON-ESM-LR__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP6.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.fx.areacella.gn.v20220111 - CMIP6.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.fx.sftlf.gn.v20220111 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_MPI-ESM-1-2-HAM__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.Amon.pr.gn.v20190627 @@ -153,7 +153,7 @@ cmip6_historical_gn_r1i1p1f1_MPI-ESM-1-2-HAM__obs4mips_gn_WECANN-1-0_gpp_v202509 - CMIP6.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.fx.areacella.gn.v20190627 - CMIP6.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.fx.sftlf.gn.v20190627 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_MPI-ESM1-2-HR__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.Amon.pr.gn.v20190710 @@ -162,7 +162,7 @@ cmip6_historical_gn_r1i1p1f1_MPI-ESM1-2-HR__obs4mips_gn_WECANN-1-0_gpp_v20250902 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.fx.areacella.gn.v20190710 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.fx.sftlf.gn.v20190710 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_MPI-ESM1-2-LR__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.Amon.pr.gn.v20190710 @@ -171,7 +171,7 @@ cmip6_historical_gn_r1i1p1f1_MPI-ESM1-2-LR__obs4mips_gn_WECANN-1-0_gpp_v20250902 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.fx.areacella.gn.v20190710 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.fx.sftlf.gn.v20190710 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_NorCPM1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.NCC.NorCPM1.historical.r1i1p1f1.Amon.pr.gn.v20200724 @@ -180,7 +180,7 @@ cmip6_historical_gn_r1i1p1f1_NorCPM1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP6.CMIP.NCC.NorCPM1.historical.r1i1p1f1.fx.areacella.gn.v20200724 - CMIP6.CMIP.NCC.NorCPM1.historical.r1i1p1f1.fx.sftlf.gn.v20200724 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_NorESM2-LM__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.Amon.pr.gn.v20190815 @@ -189,7 +189,7 @@ cmip6_historical_gn_r1i1p1f1_NorESM2-LM__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP6.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.fx.areacella.gn.v20190815 - CMIP6.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.fx.sftlf.gn.v20191108 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_NorESM2-MM__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.Amon.pr.gn.v20191108 @@ -198,7 +198,7 @@ cmip6_historical_gn_r1i1p1f1_NorESM2-MM__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP6.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.fx.areacella.gn.v20191108 - CMIP6.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.fx.sftlf.gn.v20191108 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_SAM0-UNICON__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.Amon.pr.gn.v20190323 @@ -207,7 +207,7 @@ cmip6_historical_gn_r1i1p1f1_SAM0-UNICON__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP6.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.fx.areacella.gn.v20190323 - CMIP6.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.fx.sftlf.gn.v20190323 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_TaiESM1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.Amon.pr.gn.v20200623 @@ -216,7 +216,7 @@ cmip6_historical_gn_r1i1p1f1_TaiESM1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP6.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.fx.areacella.gn.v20200624 - CMIP6.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.fx.sftlf.gn.v20200624 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f2_MIROC-ES2L__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.Amon.pr.gn.v20190823 @@ -225,21 +225,21 @@ cmip6_historical_gn_r1i1p1f2_MIROC-ES2L__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP6.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.fx.areacella.gn.v20190823 - CMIP6.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.fx.sftlf.gn.v20190823 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f2_UKESM1-0-LL__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.MOHC.UKESM1-0-LL.historical.r1i1p1f2.Amon.pr.gn.v20190406 - CMIP6.CMIP.MOHC.UKESM1-0-LL.historical.r1i1p1f2.Amon.tas.gn.v20190406 - CMIP6.CMIP.MOHC.UKESM1-0-LL.historical.r1i1p1f2.Lmon.gpp.gn.v20190627 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p1f2_UKESM1-1-LL__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.MOHC.UKESM1-1-LL.historical.r1i1p1f2.Amon.pr.gn.v20220512 - CMIP6.CMIP.MOHC.UKESM1-1-LL.historical.r1i1p1f2.Amon.tas.gn.v20220512 - CMIP6.CMIP.MOHC.UKESM1-1-LL.historical.r1i1p1f2.Lmon.gpp.gn.v20220512 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gn_r1i1p2f1_CanESM5-CanOE__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.Amon.pr.gn.v20190429 @@ -248,7 +248,7 @@ cmip6_historical_gn_r1i1p2f1_CanESM5-CanOE__obs4mips_gn_WECANN-1-0_gpp_v20250902 - CMIP6.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.fx.areacella.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.fx.sftlf.gn.v20190429 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gr1_r1i1p1f1_GFDL-ESM4__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.Amon.pr.gr1.v20190726 @@ -257,7 +257,7 @@ cmip6_historical_gr1_r1i1p1f1_GFDL-ESM4__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP6.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.fx.areacella.gr1.v20190726 - CMIP6.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.fx.sftlf.gr1.v20190726 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gr1_r1i1p1f1_INM-CM4-8__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.INM.INM-CM4-8.1pctCO2.r1i1p1f1.fx.areacella.gr1.v20190530 @@ -266,7 +266,7 @@ cmip6_historical_gr1_r1i1p1f1_INM-CM4-8__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP6.CMIP.INM.INM-CM4-8.historical.r1i1p1f1.Lmon.gpp.gr1.v20190530 - CMIP6.CMIP.INM.INM-CM4-8.historical.r1i1p1f1.fx.sftlf.gr1.v20190528 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gr1_r1i1p1f1_INM-CM5-0__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.INM.INM-CM5-0.historical.r1i1p1f1.Amon.pr.gr1.v20190610 @@ -275,14 +275,14 @@ cmip6_historical_gr1_r1i1p1f1_INM-CM5-0__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP6.CMIP.INM.INM-CM5-0.historical.r1i1p1f1.fx.areacella.gr1.v20190610 - CMIP6.CMIP.INM.INM-CM5-0.historical.r1i1p1f1.fx.sftlf.gr1.v20190610 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gr1_r1i1p1f1_KIOST-ESM__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.KIOST.KIOST-ESM.historical.r1i1p1f1.Amon.pr.gr1.v20210928 - CMIP6.CMIP.KIOST.KIOST-ESM.historical.r1i1p1f1.Amon.tas.gr1.v20210601 - CMIP6.CMIP.KIOST.KIOST-ESM.historical.r1i1p1f1.Lmon.gpp.gr1.v20210601 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gr_r1i1p101f1_GISS-E3-G__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.Amon.pr.gr.v20230320 @@ -291,7 +291,7 @@ cmip6_historical_gr_r1i1p101f1_GISS-E3-G__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP6.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.fx.areacella.gr.v20230320 - CMIP6.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.fx.sftlf.gr.v20230320 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gr_r1i1p1f1_E3SM-1-1-ECA__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.E3SM-Project.E3SM-1-1-ECA.historical.r1i1p1f1.Amon.pr.gr.v20200623 @@ -300,7 +300,7 @@ cmip6_historical_gr_r1i1p1f1_E3SM-1-1-ECA__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP6.CMIP.E3SM-Project.E3SM-1-1-ECA.historical.r1i1p1f1.fx.areacella.gr.v20200116 - CMIP6.CMIP.E3SM-Project.E3SM-1-1-ECA.historical.r1i1p1f1.fx.sftlf.gr.v20201015 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gr_r1i1p1f1_E3SM-1-1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.E3SM-Project.E3SM-1-1.historical.r1i1p1f1.Amon.pr.gr.v20191211 @@ -309,7 +309,7 @@ cmip6_historical_gr_r1i1p1f1_E3SM-1-1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP6.CMIP.E3SM-Project.E3SM-1-1.historical.r1i1p1f1.fx.areacella.gr.v20191212 - CMIP6.CMIP.E3SM-Project.E3SM-1-1.historical.r1i1p1f1.fx.sftlf.gr.v20201015 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gr_r1i1p1f1_EC-Earth3-CC__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.Amon.pr.gr.v20210113 @@ -317,7 +317,7 @@ cmip6_historical_gr_r1i1p1f1_EC-Earth3-CC__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.Lmon.gpp.gr.v20210113 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.fx.areacella.gr.v20210616 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gr_r1i1p1f1_EC-Earth3-Veg-LR__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.Amon.pr.gr.v20200217 @@ -326,7 +326,7 @@ cmip6_historical_gr_r1i1p1f1_EC-Earth3-Veg-LR__obs4mips_gn_WECANN-1-0_gpp_v20250 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.fx.areacella.gr.v20200217 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.fx.sftlf.gr.v20200217 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gr_r1i1p1f1_EC-Earth3-Veg__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r11i1p1f1.fx.areacella.gr.v20230203 @@ -335,14 +335,14 @@ cmip6_historical_gr_r1i1p1f1_EC-Earth3-Veg__obs4mips_gn_WECANN-1-0_gpp_v20250902 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.Lmon.gpp.gr.v20211207 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.fx.sftlf.gr.v20211207 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gr_r1i1p1f1_IPSL-CM6A-LR-INCA__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.IPSL.IPSL-CM6A-LR-INCA.historical.r1i1p1f1.Amon.pr.gr.v20210216 - CMIP6.CMIP.IPSL.IPSL-CM6A-LR-INCA.historical.r1i1p1f1.Amon.tas.gr.v20210216 - CMIP6.CMIP.IPSL.IPSL-CM6A-LR-INCA.historical.r1i1p1f1.Lmon.gpp.gr.v20210216 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gr_r1i1p1f1_IPSL-CM6A-LR__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.Amon.pr.gr.v20180803 @@ -351,7 +351,7 @@ cmip6_historical_gr_r1i1p1f1_IPSL-CM6A-LR__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP6.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.fx.areacella.gr.v20180803 - CMIP6.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.fx.sftlf.gr.v20180803 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gr_r1i1p1f2_CNRM-CM6-1-HR__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1-HR.historical.r1i1p1f2.Amon.pr.gr.v20191021 @@ -360,7 +360,7 @@ cmip6_historical_gr_r1i1p1f2_CNRM-CM6-1-HR__obs4mips_gn_WECANN-1-0_gpp_v20250902 - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1-HR.historical.r1i1p1f2.fx.areacella.gr.v20191021 - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1-HR.historical.r1i1p1f2.fx.sftlf.gr.v20191021 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gr_r1i1p1f2_CNRM-CM6-1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.Amon.pr.gr.v20180917 @@ -369,7 +369,7 @@ cmip6_historical_gr_r1i1p1f2_CNRM-CM6-1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.fx.areacella.gr.v20180917 - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.fx.sftlf.gr.v20180917 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip6_historical_gr_r1i1p1f2_CNRM-ESM2-1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip6: - CMIP6.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r13i1p1f2.fx.areacella.gr.v20250328 @@ -377,7 +377,7 @@ cmip6_historical_gr_r1i1p1f2_CNRM-ESM2-1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP6.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.Amon.tas.gr.v20181206 - CMIP6.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.Lmon.gpp.gr.v20181206 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_ACCESS-ESM1-5_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20191115 @@ -386,7 +386,7 @@ cmip7_historical_gn_ACCESS-ESM1-5_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902 - CMIP7.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gn.v20191115 - CMIP7.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20191115 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_AWI-ESM-1-1-LR_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20200212 @@ -395,14 +395,14 @@ cmip7_historical_gn_AWI-ESM-1-1-LR_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v2025090 - CMIP7.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gn.v20200212 - CMIP7.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20200212 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_BCC-CSM2-MR_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.BCC.BCC-CSM2-MR.historical.r1i1p1f1.glb.mon.gpp.tavg-u-hxy-lnd.gn.v20181114 - CMIP7.CMIP.BCC.BCC-CSM2-MR.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gn.v20181126 - CMIP7.CMIP.BCC.BCC-CSM2-MR.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20181126 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_BCC-ESM1_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.BCC.BCC-ESM1.1pctCO2.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190613 @@ -410,14 +410,14 @@ cmip7_historical_gn_BCC-ESM1_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP7.CMIP.BCC.BCC-ESM1.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gn.v20181214 - CMIP7.CMIP.BCC.BCC-ESM1.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20181214 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_CAS-ESM2-0_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.CAS.CAS-ESM2-0.historical.r1i1p1f1.glb.mon.gpp.tavg-u-hxy-lnd.gn.v20201224 - CMIP7.CMIP.CAS.CAS-ESM2-0.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gn.v20201227 - CMIP7.CMIP.CAS.CAS-ESM2-0.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20201227 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_CESM2-FV2_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20191120 @@ -426,7 +426,7 @@ cmip7_historical_gn_CESM2-FV2_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_CESM2-WACCM_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190227 @@ -435,7 +435,7 @@ cmip7_historical_gn_CESM2-WACCM_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP7.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gn.v20190415 - CMIP7.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20190227 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_CESM2_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190308 @@ -444,7 +444,7 @@ cmip7_historical_gn_CESM2_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gn.v20190401 - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20190308 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_CMCC-CM2-SR5_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20200616 @@ -453,7 +453,7 @@ cmip7_historical_gn_CMCC-CM2-SR5_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP7.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gn.v20200616 - CMIP7.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20200616 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_CMCC-ESM2_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20210114 @@ -462,7 +462,7 @@ cmip7_historical_gn_CMCC-ESM2_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP7.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gn.v20210114 - CMIP7.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20210114 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_CanESM5-1_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190429 @@ -471,7 +471,7 @@ cmip7_historical_gn_CanESM5-1_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP7.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20190429 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_CanESM5-CanOE_r1i1p2f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190429 @@ -480,7 +480,7 @@ cmip7_historical_gn_CanESM5-CanOE_r1i1p2f1__obs4mips_gn_WECANN-1-0_gpp_v20250902 - CMIP7.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.glb.mon.pr.tavg-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20190429 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_CanESM5_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.CCCma.CanESM5.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190429 @@ -489,42 +489,42 @@ cmip7_historical_gn_CanESM5_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP7.CMIP.CCCma.CanESM5.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20190429 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_GISS-E2-1-G-CC_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-1-G-CC.historical.r1i1p1f1.glb.mon.gpp.tavg-u-hxy-lnd.gn.v20190815 - CMIP7.CMIP.NASA-GISS.GISS-E2-1-G-CC.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gn.v20190815 - CMIP7.CMIP.NASA-GISS.GISS-E2-1-G-CC.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20190815 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_GISS-E2-1-G_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-1-G.historical.r1i1p1f1.glb.mon.gpp.tavg-u-hxy-lnd.gn.v20181015 - CMIP7.CMIP.NASA-GISS.GISS-E2-1-G.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gn.v20180827 - CMIP7.CMIP.NASA-GISS.GISS-E2-1-G.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20180827 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_GISS-E2-1-H_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-1-H.historical.r1i1p1f1.glb.mon.gpp.tavg-u-hxy-lnd.gn.v20190403 - CMIP7.CMIP.NASA-GISS.GISS-E2-1-H.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gn.v20190403 - CMIP7.CMIP.NASA-GISS.GISS-E2-1-H.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20190403 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_GISS-E2-2-G_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-2-G.historical.r1i1p1f1.glb.mon.gpp.tavg-u-hxy-lnd.gn.v20191120 - CMIP7.CMIP.NASA-GISS.GISS-E2-2-G.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NASA-GISS.GISS-E2-2-G.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_GISS-E2-2-H_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-2-H.historical.r1i1p1f1.glb.mon.gpp.tavg-u-hxy-lnd.gn.v20191120 - CMIP7.CMIP.NASA-GISS.GISS-E2-2-H.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NASA-GISS.GISS-E2-2-H.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_ICON-ESM-LR_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20220111 @@ -533,7 +533,7 @@ cmip7_historical_gn_ICON-ESM-LR_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP7.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gn.v20210215 - CMIP7.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20210215 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_MIROC-ES2L_r1i1p1f2__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.glb.fx.areacella.ti-u-hxy-u.gn.v20190823 @@ -542,7 +542,7 @@ cmip7_historical_gn_MIROC-ES2L_r1i1p1f2__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP7.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.glb.mon.pr.tavg-u-hxy-u.gn.v20190823 - CMIP7.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.glb.mon.tas.tavg-h2m-hxy-u.gn.v20190823 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_MPI-ESM-1-2-HAM_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190627 @@ -551,7 +551,7 @@ cmip7_historical_gn_MPI-ESM-1-2-HAM_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v202509 - CMIP7.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gn.v20190627 - CMIP7.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20190627 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_MPI-ESM1-2-HR_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190710 @@ -560,7 +560,7 @@ cmip7_historical_gn_MPI-ESM1-2-HR_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902 - CMIP7.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gn.v20190710 - CMIP7.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20190710 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_MPI-ESM1-2-LR_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190710 @@ -569,7 +569,7 @@ cmip7_historical_gn_MPI-ESM1-2-LR_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902 - CMIP7.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gn.v20190710 - CMIP7.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20190710 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_NorCPM1_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.NCC.NorCPM1.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20200724 @@ -578,7 +578,7 @@ cmip7_historical_gn_NorCPM1_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP7.CMIP.NCC.NorCPM1.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gn.v20200724 - CMIP7.CMIP.NCC.NorCPM1.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20200724 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_NorESM2-LM_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190815 @@ -587,7 +587,7 @@ cmip7_historical_gn_NorESM2-LM_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP7.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gn.v20190815 - CMIP7.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20190815 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_NorESM2-MM_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20191108 @@ -596,7 +596,7 @@ cmip7_historical_gn_NorESM2-MM_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP7.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gn.v20191108 - CMIP7.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20191108 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_SAM0-UNICON_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190323 @@ -605,7 +605,7 @@ cmip7_historical_gn_SAM0-UNICON_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP7.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gn.v20190323 - CMIP7.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20190323 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_TaiESM1_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20200624 @@ -614,21 +614,21 @@ cmip7_historical_gn_TaiESM1_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP7.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gn.v20200623 - CMIP7.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gn.v20200623 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_UKESM1-0-LL_r1i1p1f2__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.MOHC.UKESM1-0-LL.historical.r1i1p1f2.glb.mon.gpp.tavg-u-hxy-lnd.gn.v20190627 - CMIP7.CMIP.MOHC.UKESM1-0-LL.historical.r1i1p1f2.glb.mon.pr.tavg-u-hxy-u.gn.v20190406 - CMIP7.CMIP.MOHC.UKESM1-0-LL.historical.r1i1p1f2.glb.mon.tas.tavg-h2m-hxy-u.gn.v20190406 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gn_UKESM1-1-LL_r1i1p1f2__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.MOHC.UKESM1-1-LL.historical.r1i1p1f2.glb.mon.gpp.tavg-u-hxy-lnd.gn.v20220512 - CMIP7.CMIP.MOHC.UKESM1-1-LL.historical.r1i1p1f2.glb.mon.pr.tavg-u-hxy-u.gn.v20220512 - CMIP7.CMIP.MOHC.UKESM1-1-LL.historical.r1i1p1f2.glb.mon.tas.tavg-h2m-hxy-u.gn.v20220512 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gr1_GFDL-ESM4_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr1.v20190726 @@ -637,7 +637,7 @@ cmip7_historical_gr1_GFDL-ESM4_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP7.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gr1.v20190726 - CMIP7.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gr1.v20190726 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gr1_INM-CM4-8_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.INM.INM-CM4-8.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr1.v20190528 @@ -646,7 +646,7 @@ cmip7_historical_gr1_INM-CM4-8_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP7.CMIP.INM.INM-CM4-8.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gr1.v20190530 - CMIP7.CMIP.INM.INM-CM4-8.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gr1.v20190530 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gr1_INM-CM5-0_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.INM.INM-CM5-0.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr1.v20190610 @@ -655,14 +655,14 @@ cmip7_historical_gr1_INM-CM5-0_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP7.CMIP.INM.INM-CM5-0.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gr1.v20190610 - CMIP7.CMIP.INM.INM-CM5-0.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gr1.v20190610 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gr1_KIOST-ESM_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.KIOST.KIOST-ESM.historical.r1i1p1f1.glb.mon.gpp.tavg-u-hxy-lnd.gr1.v20210601 - CMIP7.CMIP.KIOST.KIOST-ESM.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gr1.v20210928 - CMIP7.CMIP.KIOST.KIOST-ESM.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gr1.v20210601 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gr_CNRM-CM6-1-HR_r1i1p1f2__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1-HR.historical.r1i1p1f2.glb.fx.areacella.ti-u-hxy-u.gr.v20191021 @@ -671,7 +671,7 @@ cmip7_historical_gr_CNRM-CM6-1-HR_r1i1p1f2__obs4mips_gn_WECANN-1-0_gpp_v20250902 - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1-HR.historical.r1i1p1f2.glb.mon.pr.tavg-u-hxy-u.gr.v20191021 - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1-HR.historical.r1i1p1f2.glb.mon.tas.tavg-h2m-hxy-u.gr.v20191021 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gr_CNRM-CM6-1_r1i1p1f2__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.glb.fx.areacella.ti-u-hxy-u.gr.v20180917 @@ -680,7 +680,7 @@ cmip7_historical_gr_CNRM-CM6-1_r1i1p1f2__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.glb.mon.pr.tavg-u-hxy-u.gr.v20180917 - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.glb.mon.tas.tavg-h2m-hxy-u.gr.v20180917 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gr_CNRM-ESM2-1_r1i1p1f2__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r13i1p1f2.glb.fx.areacella.ti-u-hxy-u.gr.v20250328 @@ -688,7 +688,7 @@ cmip7_historical_gr_CNRM-ESM2-1_r1i1p1f2__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP7.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.glb.mon.pr.tavg-u-hxy-u.gr.v20181206 - CMIP7.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.glb.mon.tas.tavg-h2m-hxy-u.gr.v20181206 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gr_E3SM-1-1-ECA_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.E3SM-Project.E3SM-1-1-ECA.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20200116 @@ -697,7 +697,7 @@ cmip7_historical_gr_E3SM-1-1-ECA_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP7.CMIP.E3SM-Project.E3SM-1-1-ECA.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gr.v20200623 - CMIP7.CMIP.E3SM-Project.E3SM-1-1-ECA.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gr.v20200623 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gr_E3SM-1-1_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.E3SM-Project.E3SM-1-1.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20191212 @@ -706,7 +706,7 @@ cmip7_historical_gr_E3SM-1-1_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP7.CMIP.E3SM-Project.E3SM-1-1.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gr.v20191211 - CMIP7.CMIP.E3SM-Project.E3SM-1-1.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gr.v20191211 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gr_EC-Earth3-CC_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20210616 @@ -714,7 +714,7 @@ cmip7_historical_gr_EC-Earth3-CC_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gr.v20210113 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gr.v20210113 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gr_EC-Earth3-Veg-LR_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20200217 @@ -723,7 +723,7 @@ cmip7_historical_gr_EC-Earth3-Veg-LR_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gr.v20200217 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gr.v20200217 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gr_EC-Earth3-Veg_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r11i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20230203 @@ -732,7 +732,7 @@ cmip7_historical_gr_EC-Earth3-Veg_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gr.v20211207 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gr.v20211207 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gr_GISS-E3-G_r1i1p101f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.glb.fx.areacella.ti-u-hxy-u.gr.v20230320 @@ -741,14 +741,14 @@ cmip7_historical_gr_GISS-E3-G_r1i1p101f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP7.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.glb.mon.pr.tavg-u-hxy-u.gr.v20230320 - CMIP7.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.glb.mon.tas.tavg-h2m-hxy-u.gr.v20230320 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gr_IPSL-CM6A-LR-INCA_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.IPSL.IPSL-CM6A-LR-INCA.historical.r1i1p1f1.glb.mon.gpp.tavg-u-hxy-lnd.gr.v20210216 - CMIP7.CMIP.IPSL.IPSL-CM6A-LR-INCA.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gr.v20210216 - CMIP7.CMIP.IPSL.IPSL-CM6A-LR-INCA.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gr.v20210216 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 cmip7_historical_gr_IPSL-CM6A-LR_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: cmip7: - CMIP7.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20180803 @@ -757,4 +757,4 @@ cmip7_historical_gr_IPSL-CM6A-LR_r1i1p1f1__obs4mips_gn_WECANN-1-0_gpp_v20250902: - CMIP7.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.glb.mon.pr.tavg-u-hxy-u.gr.v20180803 - CMIP7.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.glb.mon.tas.tavg-h2m-hxy-u.gr.v20180803 obs4mips: - - obs4MIPs.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 + - obs4REF.obs4REF.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250902 diff --git a/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_mrro_lora_.yml b/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_mrro_lora_.yml index 6c74ae480..b0d6fc837 100644 --- a/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_mrro_lora_.yml +++ b/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_mrro_lora_.yml @@ -4,837 +4,837 @@ cmip6_historical_gn_r1i1p1f1_ACCESS-CM2__obs4mips_gn_LORA-1-0_mrro_v20250902: - CMIP6.CMIP.CSIRO-ARCCSS.ACCESS-CM2.historical.r1i1p1f1.fx.areacella.gn.v20191108 - CMIP6.CMIP.CSIRO-ARCCSS.ACCESS-CM2.historical.r1i1p1f1.fx.sftlf.gn.v20191108 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_ACCESS-ESM1-5__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Lmon.mrro.gn.v20191115 - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.fx.areacella.gn.v20191115 - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.fx.sftlf.gn.v20191115 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_AWI-ESM-1-1-LR__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.Lmon.mrro.gn.v20200212 - CMIP6.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.fx.areacella.gn.v20200212 - CMIP6.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.fx.sftlf.gn.v20200909 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_AWI-ESM-1-REcoM__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.AWI.AWI-ESM-1-REcoM.historical.r1i1p1f1.Lmon.mrro.gn.v20230314 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_BCC-CSM2-MR__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.BCC.BCC-CSM2-MR.historical.r1i1p1f1.Lmon.mrro.gn.v20181114 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_BCC-ESM1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.BCC.BCC-ESM1.1pctCO2.r1i1p1f1.fx.areacella.gn.v20190613 - CMIP6.CMIP.BCC.BCC-ESM1.historical.r1i1p1f1.Lmon.mrro.gn.v20181114 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_CAS-ESM2-0__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.CAS.CAS-ESM2-0.historical.r1i1p1f1.Lmon.mrro.gn.v20201224 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_CESM2-FV2__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.Lmon.mrro.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.fx.areacella.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.fx.sftlf.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_CESM2-WACCM-FV2__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.Lmon.mrro.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.fx.areacella.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.fx.sftlf.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_CESM2-WACCM__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.Lmon.mrro.gn.v20190227 - CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.fx.areacella.gn.v20190227 - CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.fx.sftlf.gn.v20190227 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_CESM2__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Lmon.mrro.gn.v20190308 - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.fx.areacella.gn.v20190308 - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.fx.sftlf.gn.v20190308 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_CMCC-CM2-HR4__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.CMCC.CMCC-CM2-HR4.historical.r1i1p1f1.Lmon.mrro.gn.v20200904 - CMIP6.CMIP.CMCC.CMCC-CM2-HR4.historical.r1i1p1f1.fx.sftlf.gn.v20200904 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_CMCC-CM2-SR5__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.Lmon.mrro.gn.v20200616 - CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.fx.areacella.gn.v20200616 - CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.fx.sftlf.gn.v20200616 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_CMCC-ESM2__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.Lmon.mrro.gn.v20210114 - CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.fx.areacella.gn.v20210114 - CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.fx.sftlf.gn.v20210114 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_CanESM5-1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.Lmon.mrro.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.fx.areacella.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.fx.sftlf.gn.v20190429 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_CanESM5__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.Lmon.mrro.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.fx.areacella.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.fx.sftlf.gn.v20190429 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_FGOALS-f3-L__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.CAS.FGOALS-f3-L.historical.r1i1p1f1.Lmon.mrro.gn.v20190821 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_FGOALS-g3__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.Lmon.mrro.gn.v20190820 - CMIP6.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.fx.areacella.gn.v20210615 - CMIP6.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.fx.sftlf.gn.v20200305 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_FIO-ESM-2-0__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.FIO-QLNM.FIO-ESM-2-0.historical.r1i1p1f1.Lmon.mrro.gn.v20191127 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_GISS-E2-1-G-CC__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-1-G-CC.historical.r1i1p1f1.Lmon.mrro.gn.v20190815 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_GISS-E2-1-G__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-1-G.historical.r1i1p1f1.Lmon.mrro.gn.v20181015 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_GISS-E2-1-H__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-1-H.historical.r1i1p1f1.Lmon.mrro.gn.v20190403 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_GISS-E2-2-G__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-2-G.historical.r1i1p1f1.Lmon.mrro.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_GISS-E2-2-H__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-2-H.historical.r1i1p1f1.Lmon.mrro.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_ICON-ESM-LR__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.Lmon.mrro.gn.v20210215 - CMIP6.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.fx.areacella.gn.v20220111 - CMIP6.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.fx.sftlf.gn.v20220111 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_MCM-UA-1-0__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.UA.MCM-UA-1-0.historical.r1i1p1f1.Lmon.mrro.gn.v20190731 - CMIP6.CMIP.UA.MCM-UA-1-0.historical.r1i1p1f1.fx.areacella.gn.v20190731 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_MIROC6__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.MIROC.MIROC6.historical.r1i1p1f1.Lmon.mrro.gn.v20181212 - CMIP6.CMIP.MIROC.MIROC6.historical.r1i1p1f1.fx.areacella.gn.v20190311 - CMIP6.CMIP.MIROC.MIROC6.historical.r1i1p1f1.fx.sftlf.gn.v20190311 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_MPI-ESM-1-2-HAM__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.Lmon.mrro.gn.v20190627 - CMIP6.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.fx.areacella.gn.v20190627 - CMIP6.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.fx.sftlf.gn.v20190627 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_MPI-ESM1-2-HR__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.Lmon.mrro.gn.v20190710 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.fx.areacella.gn.v20190710 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.fx.sftlf.gn.v20190710 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_MPI-ESM1-2-LR__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.Lmon.mrro.gn.v20190710 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.fx.areacella.gn.v20190710 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.fx.sftlf.gn.v20190710 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_MRI-ESM2-0__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.Lmon.mrro.gn.v20190603 - CMIP6.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.fx.areacella.gn.v20190603 - CMIP6.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.fx.sftlf.gn.v20190603 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_NorESM2-LM__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.Lmon.mrro.gn.v20190917 - CMIP6.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.fx.areacella.gn.v20190815 - CMIP6.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.fx.sftlf.gn.v20191108 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_NorESM2-MM__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.Lmon.mrro.gn.v20191108 - CMIP6.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.fx.areacella.gn.v20191108 - CMIP6.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.fx.sftlf.gn.v20191108 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_SAM0-UNICON__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.Lmon.mrro.gn.v20190323 - CMIP6.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.fx.areacella.gn.v20190323 - CMIP6.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.fx.sftlf.gn.v20190323 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f1_TaiESM1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.Lmon.mrro.gn.v20200624 - CMIP6.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.fx.areacella.gn.v20200624 - CMIP6.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.fx.sftlf.gn.v20200624 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f2_MIROC-ES2L__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.Lmon.mrro.gn.v20190823 - CMIP6.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.fx.areacella.gn.v20190823 - CMIP6.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.fx.sftlf.gn.v20190823 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f2_UKESM1-0-LL__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.MOHC.UKESM1-0-LL.historical.r1i1p1f2.Lmon.mrro.gn.v20190406 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f2_UKESM1-1-LL__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.MOHC.UKESM1-1-LL.historical.r1i1p1f2.Lmon.mrro.gn.v20220512 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f3_HadGEM3-GC31-LL__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.MOHC.HadGEM3-GC31-LL.historical.r1i1p1f3.Lmon.mrro.gn.v20190624 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p1f3_HadGEM3-GC31-MM__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.MOHC.HadGEM3-GC31-MM.historical.r1i1p1f3.Lmon.mrro.gn.v20191207 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gn_r1i1p2f1_CanESM5-CanOE__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.Lmon.mrro.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.fx.areacella.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.fx.sftlf.gn.v20190429 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gr1_r1i1p1f1_GFDL-CM4__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.NOAA-GFDL.GFDL-CM4.historical.r1i1p1f1.Lmon.mrro.gr1.v20180701 - CMIP6.CMIP.NOAA-GFDL.GFDL-CM4.historical.r1i1p1f1.fx.areacella.gr1.v20180701 - CMIP6.CMIP.NOAA-GFDL.GFDL-CM4.historical.r1i1p1f1.fx.sftlf.gr1.v20180701 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gr1_r1i1p1f1_GFDL-ESM4__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.Lmon.mrro.gr1.v20190726 - CMIP6.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.fx.areacella.gr1.v20190726 - CMIP6.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.fx.sftlf.gr1.v20190726 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gr1_r1i1p1f1_INM-CM4-8__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.INM.INM-CM4-8.1pctCO2.r1i1p1f1.fx.areacella.gr1.v20190530 - CMIP6.CMIP.INM.INM-CM4-8.historical.r1i1p1f1.Lmon.mrro.gr1.v20190530 - CMIP6.CMIP.INM.INM-CM4-8.historical.r1i1p1f1.fx.sftlf.gr1.v20190528 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gr1_r1i1p1f1_INM-CM5-0__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.INM.INM-CM5-0.historical.r1i1p1f1.Lmon.mrro.gr1.v20190610 - CMIP6.CMIP.INM.INM-CM5-0.historical.r1i1p1f1.fx.areacella.gr1.v20190610 - CMIP6.CMIP.INM.INM-CM5-0.historical.r1i1p1f1.fx.sftlf.gr1.v20190610 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gr1_r1i1p1f1_KIOST-ESM__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.KIOST.KIOST-ESM.historical.r1i1p1f1.Lmon.mrro.gr1.v20210601 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gr_r1i1p101f1_GISS-E3-G__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.Lmon.mrro.gr.v20230320 - CMIP6.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.fx.areacella.gr.v20230320 - CMIP6.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.fx.sftlf.gr.v20230320 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gr_r1i1p1f1_CIESM__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.THU.CIESM.historical.r1i1p1f1.Lmon.mrro.gr.v20200417 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gr_r1i1p1f1_E3SM-1-0__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.E3SM-Project.E3SM-1-0.historical.r1i1p1f1.Lmon.mrro.gr.v20190913 - CMIP6.CMIP.E3SM-Project.E3SM-1-0.historical.r1i1p1f1.fx.areacella.gr.v20190919 - CMIP6.CMIP.E3SM-Project.E3SM-1-0.historical.r1i1p1f1.fx.sftlf.gr.v20201015 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gr_r1i1p1f1_E3SM-1-1-ECA__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.E3SM-Project.E3SM-1-1-ECA.historical.r1i1p1f1.Lmon.mrro.gr.v20200128 - CMIP6.CMIP.E3SM-Project.E3SM-1-1-ECA.historical.r1i1p1f1.fx.areacella.gr.v20200116 - CMIP6.CMIP.E3SM-Project.E3SM-1-1-ECA.historical.r1i1p1f1.fx.sftlf.gr.v20201015 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gr_r1i1p1f1_E3SM-1-1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.E3SM-Project.E3SM-1-1.historical.r1i1p1f1.Lmon.mrro.gr.v20200324 - CMIP6.CMIP.E3SM-Project.E3SM-1-1.historical.r1i1p1f1.fx.areacella.gr.v20191212 - CMIP6.CMIP.E3SM-Project.E3SM-1-1.historical.r1i1p1f1.fx.sftlf.gr.v20201015 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gr_r1i1p1f1_E3SM-2-0-NARRM__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.E3SM-Project.E3SM-2-0-NARRM.historical.r1i1p1f1.Lmon.mrro.gr.v20230430 - CMIP6.CMIP.E3SM-Project.E3SM-2-0-NARRM.historical.r1i1p1f1.fx.areacella.gr.v20231010 - CMIP6.CMIP.E3SM-Project.E3SM-2-0-NARRM.historical.r1i1p1f1.fx.sftlf.gr.v20231010 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gr_r1i1p1f1_E3SM-2-0__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.E3SM-Project.E3SM-2-0.historical.r1i1p1f1.Lmon.mrro.gr.v20221104 - CMIP6.CMIP.E3SM-Project.E3SM-2-0.historical.r1i1p1f1.fx.areacella.gr.v20220913 - CMIP6.CMIP.E3SM-Project.E3SM-2-0.historical.r1i1p1f1.fx.sftlf.gr.v20220912 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gr_r1i1p1f1_E3SM-2-1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.E3SM-Project.E3SM-2-1.historical.r1i1p1f1.Lmon.mrro.gr.v20240208 - CMIP6.CMIP.E3SM-Project.E3SM-2-1.historical.r1i1p1f1.fx.areacella.gr.v20240318 - CMIP6.CMIP.E3SM-Project.E3SM-2-1.historical.r1i1p1f1.fx.sftlf.gr.v20240318 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gr_r1i1p1f1_EC-Earth3-AerChem__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-AerChem.historical.r1i1p1f1.Lmon.mrro.gr.v20200624 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-AerChem.historical.r1i1p1f1.fx.areacella.gr.v20200624 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-AerChem.historical.r1i1p1f1.fx.sftlf.gr.v20200624 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gr_r1i1p1f1_EC-Earth3-CC__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.Lmon.mrro.gr.v20210113 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.fx.areacella.gr.v20210616 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gr_r1i1p1f1_EC-Earth3-Veg-LR__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.Lmon.mrro.gr.v20201116 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.fx.areacella.gr.v20200217 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.fx.sftlf.gr.v20200217 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gr_r1i1p1f1_EC-Earth3-Veg__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r11i1p1f1.fx.areacella.gr.v20230203 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.Lmon.mrro.gr.v20211207 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.fx.sftlf.gr.v20211207 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gr_r1i1p1f1_EC-Earth3__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r1i1p1f1.Lmon.mrro.gr.v20210324 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r1i1p1f1.fx.areacella.gr.v20210324 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r1i1p1f1.fx.sftlf.gr.v20200310 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gr_r1i1p1f1_IPSL-CM5A2-INCA__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.IPSL.IPSL-CM5A2-INCA.historical.r1i1p1f1.Lmon.mrro.gr.v20200729 - CMIP6.CMIP.IPSL.IPSL-CM5A2-INCA.historical.r1i1p1f1.fx.areacella.gr.v20200729 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gr_r1i1p1f1_IPSL-CM6A-LR-INCA__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.IPSL.IPSL-CM6A-LR-INCA.historical.r1i1p1f1.Lmon.mrro.gr.v20210216 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gr_r1i1p1f1_IPSL-CM6A-LR__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.Lmon.mrro.gr.v20180803 - CMIP6.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.fx.areacella.gr.v20180803 - CMIP6.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.fx.sftlf.gr.v20180803 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gr_r1i1p1f1_KACE-1-0-G__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.NIMS-KMA.KACE-1-0-G.historical.r1i1p1f1.Lmon.mrro.gr.v20190911 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gr_r1i1p1f2_CNRM-CM6-1-HR__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1-HR.historical.r1i1p1f2.Lmon.mrro.gr.v20191021 - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1-HR.historical.r1i1p1f2.fx.areacella.gr.v20191021 - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1-HR.historical.r1i1p1f2.fx.sftlf.gr.v20191021 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gr_r1i1p1f2_CNRM-CM6-1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.Lmon.mrro.gr.v20180917 - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.fx.areacella.gr.v20180917 - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.fx.sftlf.gr.v20180917 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip6_historical_gr_r1i1p1f2_CNRM-ESM2-1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip6: - CMIP6.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r13i1p1f2.fx.areacella.gr.v20250328 - CMIP6.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.Lmon.mrro.gr.v20181206 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_ACCESS-CM2_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.CSIRO-ARCCSS.ACCESS-CM2.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20191108 - CMIP7.CMIP.CSIRO-ARCCSS.ACCESS-CM2.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20191108 - CMIP7.CMIP.CSIRO-ARCCSS.ACCESS-CM2.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20191108 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_ACCESS-ESM1-5_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20191115 - CMIP7.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20191115 - CMIP7.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20191115 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_AWI-ESM-1-1-LR_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20200212 - CMIP7.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20200909 - CMIP7.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20200212 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_AWI-ESM-1-REcoM_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.AWI.AWI-ESM-1-REcoM.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20230314 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_BCC-CSM2-MR_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.BCC.BCC-CSM2-MR.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20181114 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_BCC-ESM1_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.BCC.BCC-ESM1.1pctCO2.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190613 - CMIP7.CMIP.BCC.BCC-ESM1.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20181114 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_CAS-ESM2-0_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.CAS.CAS-ESM2-0.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20201224 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_CESM2-FV2_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_CESM2-WACCM-FV2_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_CESM2-WACCM_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190227 - CMIP7.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190227 - CMIP7.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20190227 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_CESM2_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190308 - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190308 - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20190308 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_CMCC-CM2-HR4_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.CMCC.CMCC-CM2-HR4.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20200904 - CMIP7.CMIP.CMCC.CMCC-CM2-HR4.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20200904 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_CMCC-CM2-SR5_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20200616 - CMIP7.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20200616 - CMIP7.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20200616 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_CMCC-ESM2_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20210114 - CMIP7.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20210114 - CMIP7.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20210114 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_CanESM5-1_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20190429 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_CanESM5-CanOE_r1i1p2f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20190429 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_CanESM5_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.CCCma.CanESM5.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20190429 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_FGOALS-f3-L_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.CAS.FGOALS-f3-L.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20190821 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_FGOALS-g3_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20210615 - CMIP7.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20200305 - CMIP7.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20190820 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_FIO-ESM-2-0_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.FIO-QLNM.FIO-ESM-2-0.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20191127 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_GISS-E2-1-G-CC_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-1-G-CC.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20190815 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_GISS-E2-1-G_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-1-G.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20181015 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_GISS-E2-1-H_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-1-H.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20190403 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_GISS-E2-2-G_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-2-G.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_GISS-E2-2-H_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-2-H.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_HadGEM3-GC31-LL_r1i1p1f3__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.MOHC.HadGEM3-GC31-LL.historical.r1i1p1f3.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20190624 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_HadGEM3-GC31-MM_r1i1p1f3__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.MOHC.HadGEM3-GC31-MM.historical.r1i1p1f3.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20191207 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_ICON-ESM-LR_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20220111 - CMIP7.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20220111 - CMIP7.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20210215 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_MCM-UA-1-0_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.UA.MCM-UA-1-0.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190731 - CMIP7.CMIP.UA.MCM-UA-1-0.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20190731 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_MIROC-ES2L_r1i1p1f2__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.glb.fx.areacella.ti-u-hxy-u.gn.v20190823 - CMIP7.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.glb.fx.sftlf.ti-u-hxy-u.gn.v20190823 - CMIP7.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20190823 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_MIROC6_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.MIROC.MIROC6.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190311 - CMIP7.CMIP.MIROC.MIROC6.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190311 - CMIP7.CMIP.MIROC.MIROC6.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20181212 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_MPI-ESM-1-2-HAM_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190627 - CMIP7.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190627 - CMIP7.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20190627 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_MPI-ESM1-2-HR_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190710 - CMIP7.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190710 - CMIP7.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20190710 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_MPI-ESM1-2-LR_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190710 - CMIP7.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190710 - CMIP7.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20190710 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_MRI-ESM2-0_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190603 - CMIP7.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190603 - CMIP7.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20190603 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_NorESM2-LM_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190815 - CMIP7.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20191108 - CMIP7.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20190917 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_NorESM2-MM_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20191108 - CMIP7.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20191108 - CMIP7.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20191108 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_SAM0-UNICON_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190323 - CMIP7.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190323 - CMIP7.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20190323 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_TaiESM1_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20200624 - CMIP7.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20200624 - CMIP7.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20200624 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_UKESM1-0-LL_r1i1p1f2__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.MOHC.UKESM1-0-LL.historical.r1i1p1f2.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20190406 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gn_UKESM1-1-LL_r1i1p1f2__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.MOHC.UKESM1-1-LL.historical.r1i1p1f2.glb.mon.mrro.tavg-u-hxy-lnd.gn.v20220512 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gr1_GFDL-CM4_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.NOAA-GFDL.GFDL-CM4.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr1.v20180701 - CMIP7.CMIP.NOAA-GFDL.GFDL-CM4.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr1.v20180701 - CMIP7.CMIP.NOAA-GFDL.GFDL-CM4.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gr1.v20180701 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gr1_GFDL-ESM4_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr1.v20190726 - CMIP7.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr1.v20190726 - CMIP7.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gr1.v20190726 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gr1_INM-CM4-8_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.INM.INM-CM4-8.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr1.v20190528 - CMIP7.CMIP.INM.INM-CM4-8.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr1.v20190528 - CMIP7.CMIP.INM.INM-CM4-8.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gr1.v20190530 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gr1_INM-CM5-0_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.INM.INM-CM5-0.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr1.v20190610 - CMIP7.CMIP.INM.INM-CM5-0.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr1.v20190610 - CMIP7.CMIP.INM.INM-CM5-0.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gr1.v20190610 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gr1_KIOST-ESM_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.KIOST.KIOST-ESM.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gr1.v20210601 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gr_CIESM_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.THU.CIESM.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gr.v20200417 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gr_CNRM-CM6-1-HR_r1i1p1f2__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1-HR.historical.r1i1p1f2.glb.fx.areacella.ti-u-hxy-u.gr.v20191021 - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1-HR.historical.r1i1p1f2.glb.fx.sftlf.ti-u-hxy-u.gr.v20191021 - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1-HR.historical.r1i1p1f2.glb.mon.mrro.tavg-u-hxy-lnd.gr.v20191021 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gr_CNRM-CM6-1_r1i1p1f2__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.glb.fx.areacella.ti-u-hxy-u.gr.v20180917 - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.glb.fx.sftlf.ti-u-hxy-u.gr.v20180917 - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.glb.mon.mrro.tavg-u-hxy-lnd.gr.v20180917 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gr_CNRM-ESM2-1_r1i1p1f2__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r13i1p1f2.glb.fx.areacella.ti-u-hxy-u.gr.v20250328 - CMIP7.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.glb.mon.mrro.tavg-u-hxy-lnd.gr.v20181206 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gr_E3SM-1-0_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.E3SM-Project.E3SM-1-0.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20190919 - CMIP7.CMIP.E3SM-Project.E3SM-1-0.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20201015 - CMIP7.CMIP.E3SM-Project.E3SM-1-0.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gr.v20190913 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gr_E3SM-1-1-ECA_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.E3SM-Project.E3SM-1-1-ECA.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20200116 - CMIP7.CMIP.E3SM-Project.E3SM-1-1-ECA.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20201015 - CMIP7.CMIP.E3SM-Project.E3SM-1-1-ECA.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gr.v20200128 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gr_E3SM-1-1_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.E3SM-Project.E3SM-1-1.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20191212 - CMIP7.CMIP.E3SM-Project.E3SM-1-1.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20201015 - CMIP7.CMIP.E3SM-Project.E3SM-1-1.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gr.v20200324 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gr_E3SM-2-0-NARRM_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.E3SM-Project.E3SM-2-0-NARRM.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20231010 - CMIP7.CMIP.E3SM-Project.E3SM-2-0-NARRM.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20231010 - CMIP7.CMIP.E3SM-Project.E3SM-2-0-NARRM.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gr.v20230430 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gr_E3SM-2-0_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.E3SM-Project.E3SM-2-0.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20220913 - CMIP7.CMIP.E3SM-Project.E3SM-2-0.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20220912 - CMIP7.CMIP.E3SM-Project.E3SM-2-0.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gr.v20221104 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gr_E3SM-2-1_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.E3SM-Project.E3SM-2-1.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20240318 - CMIP7.CMIP.E3SM-Project.E3SM-2-1.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20240318 - CMIP7.CMIP.E3SM-Project.E3SM-2-1.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gr.v20240208 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gr_EC-Earth3-AerChem_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-AerChem.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20200624 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-AerChem.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20200624 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-AerChem.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gr.v20200624 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gr_EC-Earth3-CC_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20210616 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gr.v20210113 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gr_EC-Earth3-Veg-LR_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20200217 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20200217 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gr.v20201116 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gr_EC-Earth3-Veg_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r11i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20230203 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20211207 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gr.v20211207 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gr_EC-Earth3_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20210324 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20200310 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gr.v20210324 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gr_GISS-E3-G_r1i1p101f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.glb.fx.areacella.ti-u-hxy-u.gr.v20230320 - CMIP7.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20230320 - CMIP7.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.glb.mon.mrro.tavg-u-hxy-lnd.gr.v20230320 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gr_IPSL-CM5A2-INCA_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.IPSL.IPSL-CM5A2-INCA.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20200729 - CMIP7.CMIP.IPSL.IPSL-CM5A2-INCA.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gr.v20200729 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gr_IPSL-CM6A-LR-INCA_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.IPSL.IPSL-CM6A-LR-INCA.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gr.v20210216 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gr_IPSL-CM6A-LR_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20180803 - CMIP7.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20180803 - CMIP7.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gr.v20180803 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 cmip7_historical_gr_KACE-1-0-G_r1i1p1f1__obs4mips_gn_LORA-1-0_mrro_v20250902: cmip7: - CMIP7.CMIP.NIMS-KMA.KACE-1-0-G.historical.r1i1p1f1.glb.mon.mrro.tavg-u-hxy-lnd.gr.v20190911 obs4mips: - - obs4MIPs.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 + - obs4REF.obs4REF.ARCCSS.LORA-1-0.mon.mrro.50km.gn.v20250902 diff --git a/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_nbp_hoffman_.yml b/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_nbp_hoffman_.yml index f9c15aed7..3ae3d8c95 100644 --- a/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_nbp_hoffman_.yml +++ b/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_nbp_hoffman_.yml @@ -4,477 +4,477 @@ cmip6_historical_gn_r1i1p1f1_ACCESS-ESM1-5__obs4mips_gm_Hoffman-1-0_nbp_v2025111 - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.fx.areacella.gn.v20191115 - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.fx.sftlf.gn.v20191115 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gn_r1i1p1f1_CESM2-FV2__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.Lmon.nbp.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.fx.areacella.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.fx.sftlf.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gn_r1i1p1f1_CESM2-WACCM-FV2__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.Lmon.nbp.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.fx.areacella.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.fx.sftlf.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gn_r1i1p1f1_CESM2-WACCM__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.Lmon.nbp.gn.v20190227 - CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.fx.areacella.gn.v20190227 - CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.fx.sftlf.gn.v20190227 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gn_r1i1p1f1_CESM2__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Lmon.nbp.gn.v20190308 - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.fx.areacella.gn.v20190308 - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.fx.sftlf.gn.v20190308 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gn_r1i1p1f1_CMCC-CM2-SR5__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.Lmon.nbp.gn.v20200616 - CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.fx.areacella.gn.v20200616 - CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.fx.sftlf.gn.v20200616 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gn_r1i1p1f1_CMCC-ESM2__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.Lmon.nbp.gn.v20210114 - CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.fx.areacella.gn.v20210114 - CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.fx.sftlf.gn.v20210114 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gn_r1i1p1f1_CanESM5-1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.Lmon.nbp.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.fx.areacella.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.fx.sftlf.gn.v20190429 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gn_r1i1p1f1_CanESM5__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.Lmon.nbp.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.fx.areacella.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.fx.sftlf.gn.v20190429 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gn_r1i1p1f1_GISS-E2-1-G-CC__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-1-G-CC.historical.r1i1p1f1.Lmon.nbp.gn.v20190815 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gn_r1i1p1f1_GISS-E2-1-G__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-1-G.historical.r1i1p1f1.Lmon.nbp.gn.v20181015 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gn_r1i1p1f1_GISS-E2-1-H__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-1-H.historical.r1i1p1f1.Lmon.nbp.gn.v20190403 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gn_r1i1p1f1_GISS-E2-2-G__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-2-G.historical.r1i1p1f1.Lmon.nbp.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gn_r1i1p1f1_GISS-E2-2-H__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-2-H.historical.r1i1p1f1.Lmon.nbp.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gn_r1i1p1f1_MPI-ESM-1-2-HAM__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.Lmon.nbp.gn.v20190627 - CMIP6.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.fx.areacella.gn.v20190627 - CMIP6.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.fx.sftlf.gn.v20190627 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gn_r1i1p1f1_MPI-ESM1-2-LR__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.Lmon.nbp.gn.v20190710 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.fx.areacella.gn.v20190710 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.fx.sftlf.gn.v20190710 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gn_r1i1p1f1_NorCPM1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.NCC.NorCPM1.historical.r1i1p1f1.Lmon.nbp.gn.v20200724 - CMIP6.CMIP.NCC.NorCPM1.historical.r1i1p1f1.fx.areacella.gn.v20200724 - CMIP6.CMIP.NCC.NorCPM1.historical.r1i1p1f1.fx.sftlf.gn.v20200724 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gn_r1i1p1f1_NorESM2-LM__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.Lmon.nbp.gn.v20190917 - CMIP6.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.fx.areacella.gn.v20190815 - CMIP6.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.fx.sftlf.gn.v20191108 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gn_r1i1p1f1_NorESM2-MM__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.Lmon.nbp.gn.v20191108 - CMIP6.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.fx.areacella.gn.v20191108 - CMIP6.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.fx.sftlf.gn.v20191108 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gn_r1i1p1f1_SAM0-UNICON__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.Lmon.nbp.gn.v20190323 - CMIP6.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.fx.areacella.gn.v20190323 - CMIP6.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.fx.sftlf.gn.v20190323 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gn_r1i1p1f1_TaiESM1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.Lmon.nbp.gn.v20200624 - CMIP6.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.fx.areacella.gn.v20200624 - CMIP6.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.fx.sftlf.gn.v20200624 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gn_r1i1p1f2_MIROC-ES2L__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.Lmon.nbp.gn.v20190823 - CMIP6.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.fx.areacella.gn.v20190823 - CMIP6.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.fx.sftlf.gn.v20190823 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gn_r1i1p1f2_UKESM1-0-LL__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.MOHC.UKESM1-0-LL.historical.r1i1p1f2.Lmon.nbp.gn.v20190627 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gn_r1i1p1f2_UKESM1-1-LL__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.MOHC.UKESM1-1-LL.historical.r1i1p1f2.Lmon.nbp.gn.v20220512 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gn_r1i1p2f1_CanESM5-CanOE__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.Lmon.nbp.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.fx.areacella.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.fx.sftlf.gn.v20190429 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gr1_r1i1p1f1_GFDL-ESM4__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.Lmon.nbp.gr1.v20190726 - CMIP6.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.fx.areacella.gr1.v20190726 - CMIP6.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.fx.sftlf.gr1.v20190726 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gr1_r1i1p1f1_INM-CM4-8__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.INM.INM-CM4-8.1pctCO2.r1i1p1f1.fx.areacella.gr1.v20190530 - CMIP6.CMIP.INM.INM-CM4-8.historical.r1i1p1f1.Lmon.nbp.gr1.v20190530 - CMIP6.CMIP.INM.INM-CM4-8.historical.r1i1p1f1.fx.sftlf.gr1.v20190528 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gr1_r1i1p1f1_INM-CM5-0__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.INM.INM-CM5-0.historical.r1i1p1f1.Lmon.nbp.gr1.v20190610 - CMIP6.CMIP.INM.INM-CM5-0.historical.r1i1p1f1.fx.areacella.gr1.v20190610 - CMIP6.CMIP.INM.INM-CM5-0.historical.r1i1p1f1.fx.sftlf.gr1.v20190610 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gr_r1i1p1f1_E3SM-1-1-ECA__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.E3SM-Project.E3SM-1-1-ECA.historical.r1i1p1f1.Lmon.nbp.gr.v20220127 - CMIP6.CMIP.E3SM-Project.E3SM-1-1-ECA.historical.r1i1p1f1.fx.areacella.gr.v20200116 - CMIP6.CMIP.E3SM-Project.E3SM-1-1-ECA.historical.r1i1p1f1.fx.sftlf.gr.v20201015 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gr_r1i1p1f1_E3SM-1-1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.E3SM-Project.E3SM-1-1.historical.r1i1p1f1.Lmon.nbp.gr.v20220127 - CMIP6.CMIP.E3SM-Project.E3SM-1-1.historical.r1i1p1f1.fx.areacella.gr.v20191212 - CMIP6.CMIP.E3SM-Project.E3SM-1-1.historical.r1i1p1f1.fx.sftlf.gr.v20201015 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gr_r1i1p1f1_EC-Earth3-CC__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.Lmon.nbp.gr.v20210113 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.fx.areacella.gr.v20210616 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gr_r1i1p1f1_EC-Earth3-Veg-LR__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.Lmon.nbp.gr.v20201116 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.fx.areacella.gr.v20200217 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.fx.sftlf.gr.v20200217 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gr_r1i1p1f1_EC-Earth3-Veg__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r11i1p1f1.fx.areacella.gr.v20230203 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.Lmon.nbp.gr.v20211207 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.fx.sftlf.gr.v20211207 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gr_r1i1p1f1_IPSL-CM5A2-INCA__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.IPSL.IPSL-CM5A2-INCA.historical.r1i1p1f1.Lmon.nbp.gr.v20200729 - CMIP6.CMIP.IPSL.IPSL-CM5A2-INCA.historical.r1i1p1f1.fx.areacella.gr.v20200729 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gr_r1i1p1f1_IPSL-CM6A-LR-INCA__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.IPSL.IPSL-CM6A-LR-INCA.historical.r1i1p1f1.Lmon.nbp.gr.v20210216 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gr_r1i1p1f1_IPSL-CM6A-LR__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.Lmon.nbp.gr.v20180803 - CMIP6.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.fx.areacella.gr.v20180803 - CMIP6.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.fx.sftlf.gr.v20180803 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip6_historical_gr_r1i1p1f2_CNRM-ESM2-1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip6: - CMIP6.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r13i1p1f2.fx.areacella.gr.v20250328 - CMIP6.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.Lmon.nbp.gr.v20181206 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gn_ACCESS-ESM1-5_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20191115 - CMIP7.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20191115 - CMIP7.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gn.v20191115 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gn_CESM2-FV2_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gn_CESM2-WACCM-FV2_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gn_CESM2-WACCM_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190227 - CMIP7.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190227 - CMIP7.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gn.v20190227 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gn_CESM2_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190308 - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190308 - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gn.v20190308 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gn_CMCC-CM2-SR5_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20200616 - CMIP7.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20200616 - CMIP7.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gn.v20200616 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gn_CMCC-ESM2_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20210114 - CMIP7.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20210114 - CMIP7.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gn.v20210114 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gn_CanESM5-1_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gn.v20190429 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gn_CanESM5-CanOE_r1i1p2f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.glb.mon.nbp.tavg-u-hxy-lnd.gn.v20190429 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gn_CanESM5_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.CCCma.CanESM5.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gn.v20190429 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gn_GISS-E2-1-G-CC_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-1-G-CC.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gn.v20190815 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gn_GISS-E2-1-G_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-1-G.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gn.v20181015 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gn_GISS-E2-1-H_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-1-H.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gn.v20190403 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gn_GISS-E2-2-G_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-2-G.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gn_GISS-E2-2-H_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-2-H.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gn_MIROC-ES2L_r1i1p1f2__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.glb.fx.areacella.ti-u-hxy-u.gn.v20190823 - CMIP7.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.glb.fx.sftlf.ti-u-hxy-u.gn.v20190823 - CMIP7.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.glb.mon.nbp.tavg-u-hxy-lnd.gn.v20190823 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gn_MPI-ESM-1-2-HAM_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190627 - CMIP7.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190627 - CMIP7.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gn.v20190627 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gn_MPI-ESM1-2-LR_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190710 - CMIP7.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190710 - CMIP7.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gn.v20190710 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gn_NorCPM1_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.NCC.NorCPM1.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20200724 - CMIP7.CMIP.NCC.NorCPM1.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20200724 - CMIP7.CMIP.NCC.NorCPM1.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gn.v20200724 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gn_NorESM2-LM_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190815 - CMIP7.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20191108 - CMIP7.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gn.v20190917 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gn_NorESM2-MM_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20191108 - CMIP7.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20191108 - CMIP7.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gn.v20191108 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gn_SAM0-UNICON_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190323 - CMIP7.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190323 - CMIP7.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gn.v20190323 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gn_TaiESM1_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20200624 - CMIP7.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20200624 - CMIP7.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gn.v20200624 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gn_UKESM1-0-LL_r1i1p1f2__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.MOHC.UKESM1-0-LL.historical.r1i1p1f2.glb.mon.nbp.tavg-u-hxy-lnd.gn.v20190627 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gn_UKESM1-1-LL_r1i1p1f2__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.MOHC.UKESM1-1-LL.historical.r1i1p1f2.glb.mon.nbp.tavg-u-hxy-lnd.gn.v20220512 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gr1_GFDL-ESM4_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr1.v20190726 - CMIP7.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr1.v20190726 - CMIP7.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gr1.v20190726 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gr1_INM-CM4-8_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.INM.INM-CM4-8.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr1.v20190528 - CMIP7.CMIP.INM.INM-CM4-8.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr1.v20190528 - CMIP7.CMIP.INM.INM-CM4-8.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gr1.v20190530 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gr1_INM-CM5-0_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.INM.INM-CM5-0.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr1.v20190610 - CMIP7.CMIP.INM.INM-CM5-0.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr1.v20190610 - CMIP7.CMIP.INM.INM-CM5-0.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gr1.v20190610 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gr_CNRM-ESM2-1_r1i1p1f2__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r13i1p1f2.glb.fx.areacella.ti-u-hxy-u.gr.v20250328 - CMIP7.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.glb.mon.nbp.tavg-u-hxy-lnd.gr.v20181206 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gr_E3SM-1-1-ECA_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.E3SM-Project.E3SM-1-1-ECA.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20200116 - CMIP7.CMIP.E3SM-Project.E3SM-1-1-ECA.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20201015 - CMIP7.CMIP.E3SM-Project.E3SM-1-1-ECA.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gr.v20220127 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gr_E3SM-1-1_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.E3SM-Project.E3SM-1-1.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20191212 - CMIP7.CMIP.E3SM-Project.E3SM-1-1.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20201015 - CMIP7.CMIP.E3SM-Project.E3SM-1-1.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gr.v20220127 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gr_EC-Earth3-CC_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20210616 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gr.v20210113 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gr_EC-Earth3-Veg-LR_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20200217 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20200217 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gr.v20201116 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gr_EC-Earth3-Veg_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r11i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20230203 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20211207 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gr.v20211207 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gr_IPSL-CM5A2-INCA_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.IPSL.IPSL-CM5A2-INCA.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20200729 - CMIP7.CMIP.IPSL.IPSL-CM5A2-INCA.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gr.v20200729 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gr_IPSL-CM6A-LR-INCA_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.IPSL.IPSL-CM6A-LR-INCA.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gr.v20210216 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 cmip7_historical_gr_IPSL-CM6A-LR_r1i1p1f1__obs4mips_gm_Hoffman-1-0_nbp_v20251117: cmip7: - CMIP7.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20180803 - CMIP7.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20180803 - CMIP7.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.glb.mon.nbp.tavg-u-hxy-lnd.gr.v20180803 obs4mips: - - obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 + - obs4REF.obs4REF.UCI-ORNL.Hoffman-1-0.yr.nbp.site.gm.v20251117 diff --git a/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_snc_esacci_.yml b/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_snc_esacci_.yml index 087f78aa5..5ca6e23ad 100644 --- a/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_snc_esacci_.yml +++ b/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_snc_esacci_.yml @@ -4,659 +4,659 @@ cmip6_historical_gn_r1i1p1f1_AWI-ESM-1-1-LR__obs4mips_gn_CCI-CryoClim-FSC-1_snc_ - CMIP6.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.fx.areacella.gn.v20200212 - CMIP6.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.fx.sftlf.gn.v20200909 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_BCC-CSM2-MR__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.BCC.BCC-CSM2-MR.historical.r1i1p1f1.LImon.snc.gn.v20181114 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_BCC-ESM1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.BCC.BCC-ESM1.1pctCO2.r1i1p1f1.fx.areacella.gn.v20190613 - CMIP6.CMIP.BCC.BCC-ESM1.historical.r1i1p1f1.LImon.snc.gn.v20181114 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_CAS-ESM2-0__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.CAS.CAS-ESM2-0.historical.r1i1p1f1.LImon.snc.gn.v20201224 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_CESM2-FV2__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.LImon.snc.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.fx.areacella.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.fx.sftlf.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_CESM2-WACCM-FV2__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.LImon.snc.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.fx.areacella.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.fx.sftlf.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_CESM2-WACCM__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.LImon.snc.gn.v20190227 - CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.fx.areacella.gn.v20190227 - CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.fx.sftlf.gn.v20190227 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_CESM2__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.LImon.snc.gn.v20190308 - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.fx.areacella.gn.v20190308 - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.fx.sftlf.gn.v20190308 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_CMCC-CM2-HR4__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.CMCC.CMCC-CM2-HR4.historical.r1i1p1f1.LImon.snc.gn.v20200904 - CMIP6.CMIP.CMCC.CMCC-CM2-HR4.historical.r1i1p1f1.fx.sftlf.gn.v20200904 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_CMCC-CM2-SR5__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.LImon.snc.gn.v20200616 - CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.fx.areacella.gn.v20200616 - CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.fx.sftlf.gn.v20200616 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_CMCC-ESM2__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.LImon.snc.gn.v20210114 - CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.fx.areacella.gn.v20210114 - CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.fx.sftlf.gn.v20210114 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_CanESM5-1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.LImon.snc.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.fx.areacella.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.fx.sftlf.gn.v20190429 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_CanESM5__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.LImon.snc.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.fx.areacella.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.fx.sftlf.gn.v20190429 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_FGOALS-f3-L__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.CAS.FGOALS-f3-L.historical.r1i1p1f1.LImon.snc.gn.v20190821 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_FGOALS-g3__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.LImon.snc.gn.v20190820 - CMIP6.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.fx.areacella.gn.v20210615 - CMIP6.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.fx.sftlf.gn.v20200305 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_GISS-E2-1-G-CC__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-1-G-CC.historical.r1i1p1f1.LImon.snc.gn.v20190815 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_GISS-E2-1-G__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-1-G.historical.r1i1p1f1.LImon.snc.gn.v20181015 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_GISS-E2-1-H__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-1-H.historical.r1i1p1f1.LImon.snc.gn.v20190403 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_GISS-E2-2-G__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-2-G.historical.r1i1p1f1.LImon.snc.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_GISS-E2-2-H__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-2-H.historical.r1i1p1f1.LImon.snc.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_ICON-ESM-LR__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.LImon.snc.gn.v20210215 - CMIP6.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.fx.areacella.gn.v20220111 - CMIP6.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.fx.sftlf.gn.v20220111 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_MIROC6__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.MIROC.MIROC6.historical.r1i1p1f1.LImon.snc.gn.v20181212 - CMIP6.CMIP.MIROC.MIROC6.historical.r1i1p1f1.fx.areacella.gn.v20190311 - CMIP6.CMIP.MIROC.MIROC6.historical.r1i1p1f1.fx.sftlf.gn.v20190311 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_MPI-ESM-1-2-HAM__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.LImon.snc.gn.v20190627 - CMIP6.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.fx.areacella.gn.v20190627 - CMIP6.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.fx.sftlf.gn.v20190627 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_MPI-ESM1-2-HR__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.LImon.snc.gn.v20190710 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.fx.areacella.gn.v20190710 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.fx.sftlf.gn.v20190710 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_MPI-ESM1-2-LR__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.LImon.snc.gn.v20190710 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.fx.areacella.gn.v20190710 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.fx.sftlf.gn.v20190710 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_MRI-ESM2-0__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.LImon.snc.gn.v20190603 - CMIP6.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.fx.areacella.gn.v20190603 - CMIP6.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.fx.sftlf.gn.v20190603 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_NorCPM1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.NCC.NorCPM1.historical.r1i1p1f1.LImon.snc.gn.v20200724 - CMIP6.CMIP.NCC.NorCPM1.historical.r1i1p1f1.fx.areacella.gn.v20200724 - CMIP6.CMIP.NCC.NorCPM1.historical.r1i1p1f1.fx.sftlf.gn.v20200724 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_NorESM2-LM__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.LImon.snc.gn.v20190917 - CMIP6.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.fx.areacella.gn.v20190815 - CMIP6.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.fx.sftlf.gn.v20191108 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_NorESM2-MM__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.LImon.snc.gn.v20191108 - CMIP6.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.fx.areacella.gn.v20191108 - CMIP6.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.fx.sftlf.gn.v20191108 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_SAM0-UNICON__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.LImon.snc.gn.v20190323 - CMIP6.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.fx.areacella.gn.v20190323 - CMIP6.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.fx.sftlf.gn.v20190323 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f1_TaiESM1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.LImon.snc.gn.v20200626 - CMIP6.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.fx.areacella.gn.v20200624 - CMIP6.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.fx.sftlf.gn.v20200624 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f2_MIROC-ES2L__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.LImon.snc.gn.v20190823 - CMIP6.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.fx.areacella.gn.v20190823 - CMIP6.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.fx.sftlf.gn.v20190823 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f2_UKESM1-0-LL__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.MOHC.UKESM1-0-LL.historical.r1i1p1f2.LImon.snc.gn.v20190406 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f2_UKESM1-1-LL__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.MOHC.UKESM1-1-LL.historical.r1i1p1f2.LImon.snc.gn.v20220512 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f3_HadGEM3-GC31-LL__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.MOHC.HadGEM3-GC31-LL.historical.r1i1p1f3.LImon.snc.gn.v20190624 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p1f3_HadGEM3-GC31-MM__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.MOHC.HadGEM3-GC31-MM.historical.r1i1p1f3.LImon.snc.gn.v20191207 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gn_r1i1p2f1_CanESM5-CanOE__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.LImon.snc.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.fx.areacella.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.fx.sftlf.gn.v20190429 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gr1_r1i1p1f1_GFDL-CM4__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.NOAA-GFDL.GFDL-CM4.historical.r1i1p1f1.LImon.snc.gr1.v20180701 - CMIP6.CMIP.NOAA-GFDL.GFDL-CM4.historical.r1i1p1f1.fx.areacella.gr1.v20180701 - CMIP6.CMIP.NOAA-GFDL.GFDL-CM4.historical.r1i1p1f1.fx.sftlf.gr1.v20180701 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gr1_r1i1p1f1_GFDL-ESM4__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.LImon.snc.gr1.v20180701 - CMIP6.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.fx.areacella.gr1.v20190726 - CMIP6.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.fx.sftlf.gr1.v20190726 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gr_r1i1p101f1_GISS-E3-G__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.LImon.snc.gr.v20230320 - CMIP6.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.fx.areacella.gr.v20230320 - CMIP6.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.fx.sftlf.gr.v20230320 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gr_r1i1p1f1_CIESM__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.THU.CIESM.historical.r1i1p1f1.LImon.snc.gr.v20200417 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gr_r1i1p1f1_EC-Earth3-AerChem__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-AerChem.historical.r1i1p1f1.LImon.snc.gr.v20200624 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-AerChem.historical.r1i1p1f1.fx.areacella.gr.v20200624 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-AerChem.historical.r1i1p1f1.fx.sftlf.gr.v20200624 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gr_r1i1p1f1_EC-Earth3-CC__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.LImon.snc.gr.v20210113 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.fx.areacella.gr.v20210616 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gr_r1i1p1f1_EC-Earth3-Veg-LR__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.LImon.snc.gr.v20200217 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.fx.areacella.gr.v20200217 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.fx.sftlf.gr.v20200217 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gr_r1i1p1f1_EC-Earth3-Veg__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r11i1p1f1.fx.areacella.gr.v20230203 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.LImon.snc.gr.v20211207 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.fx.sftlf.gr.v20211207 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gr_r1i1p1f1_EC-Earth3__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r1i1p1f1.LImon.snc.gr.v20200310 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r1i1p1f1.fx.areacella.gr.v20210324 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r1i1p1f1.fx.sftlf.gr.v20200310 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gr_r1i1p1f1_IPSL-CM5A2-INCA__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.IPSL.IPSL-CM5A2-INCA.historical.r1i1p1f1.LImon.snc.gr.v20200729 - CMIP6.CMIP.IPSL.IPSL-CM5A2-INCA.historical.r1i1p1f1.fx.areacella.gr.v20200729 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gr_r1i1p1f1_IPSL-CM6A-LR-INCA__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.IPSL.IPSL-CM6A-LR-INCA.historical.r1i1p1f1.LImon.snc.gr.v20210216 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gr_r1i1p1f1_IPSL-CM6A-LR__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.LImon.snc.gr.v20180803 - CMIP6.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.fx.areacella.gr.v20180803 - CMIP6.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.fx.sftlf.gr.v20180803 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gr_r1i1p1f2_CNRM-CM6-1-HR__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1-HR.historical.r1i1p1f2.LImon.snc.gr.v20191021 - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1-HR.historical.r1i1p1f2.fx.areacella.gr.v20191021 - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1-HR.historical.r1i1p1f2.fx.sftlf.gr.v20191021 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gr_r1i1p1f2_CNRM-CM6-1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.LImon.snc.gr.v20180917 - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.fx.areacella.gr.v20180917 - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.fx.sftlf.gr.v20180917 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip6_historical_gr_r1i1p1f2_CNRM-ESM2-1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip6: - CMIP6.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r13i1p1f2.fx.areacella.gr.v20250328 - CMIP6.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.LImon.snc.gr.v20181206 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_AWI-ESM-1-1-LR_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20200212 - CMIP7.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20200909 - CMIP7.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20200212 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_BCC-CSM2-MR_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.BCC.BCC-CSM2-MR.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20181114 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_BCC-ESM1_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.BCC.BCC-ESM1.1pctCO2.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190613 - CMIP7.CMIP.BCC.BCC-ESM1.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20181114 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_CAS-ESM2-0_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.CAS.CAS-ESM2-0.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20201224 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_CESM2-FV2_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_CESM2-WACCM-FV2_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_CESM2-WACCM_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190227 - CMIP7.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190227 - CMIP7.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20190227 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_CESM2_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190308 - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190308 - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20190308 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_CMCC-CM2-HR4_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.CMCC.CMCC-CM2-HR4.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20200904 - CMIP7.CMIP.CMCC.CMCC-CM2-HR4.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20200904 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_CMCC-CM2-SR5_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20200616 - CMIP7.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20200616 - CMIP7.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20200616 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_CMCC-ESM2_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20210114 - CMIP7.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20210114 - CMIP7.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20210114 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_CanESM5-1_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20190429 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_CanESM5-CanOE_r1i1p2f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20190429 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_CanESM5_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.CCCma.CanESM5.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20190429 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_FGOALS-f3-L_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.CAS.FGOALS-f3-L.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20190821 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_FGOALS-g3_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20210615 - CMIP7.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20200305 - CMIP7.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20190820 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_GISS-E2-1-G-CC_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-1-G-CC.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20190815 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_GISS-E2-1-G_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-1-G.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20181015 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_GISS-E2-1-H_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-1-H.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20190403 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_GISS-E2-2-G_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-2-G.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_GISS-E2-2-H_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-2-H.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20191120 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_HadGEM3-GC31-LL_r1i1p1f3__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.MOHC.HadGEM3-GC31-LL.historical.r1i1p1f3.glb.mon.snc.tavg-u-hxy-lnd.gn.v20190624 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_HadGEM3-GC31-MM_r1i1p1f3__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.MOHC.HadGEM3-GC31-MM.historical.r1i1p1f3.glb.mon.snc.tavg-u-hxy-lnd.gn.v20191207 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_ICON-ESM-LR_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20220111 - CMIP7.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20220111 - CMIP7.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20210215 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_MIROC-ES2L_r1i1p1f2__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.glb.fx.areacella.ti-u-hxy-u.gn.v20190823 - CMIP7.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.glb.fx.sftlf.ti-u-hxy-u.gn.v20190823 - CMIP7.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.glb.mon.snc.tavg-u-hxy-lnd.gn.v20190823 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_MIROC6_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.MIROC.MIROC6.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190311 - CMIP7.CMIP.MIROC.MIROC6.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190311 - CMIP7.CMIP.MIROC.MIROC6.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20181212 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_MPI-ESM-1-2-HAM_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190627 - CMIP7.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190627 - CMIP7.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20190627 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_MPI-ESM1-2-HR_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190710 - CMIP7.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190710 - CMIP7.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20190710 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_MPI-ESM1-2-LR_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190710 - CMIP7.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190710 - CMIP7.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20190710 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_MRI-ESM2-0_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190603 - CMIP7.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190603 - CMIP7.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20190603 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_NorCPM1_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.NCC.NorCPM1.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20200724 - CMIP7.CMIP.NCC.NorCPM1.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20200724 - CMIP7.CMIP.NCC.NorCPM1.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20200724 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_NorESM2-LM_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190815 - CMIP7.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20191108 - CMIP7.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20190917 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_NorESM2-MM_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20191108 - CMIP7.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20191108 - CMIP7.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20191108 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_SAM0-UNICON_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20190323 - CMIP7.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20190323 - CMIP7.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20190323 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_TaiESM1_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gn.v20200624 - CMIP7.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gn.v20200624 - CMIP7.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gn.v20200626 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_UKESM1-0-LL_r1i1p1f2__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.MOHC.UKESM1-0-LL.historical.r1i1p1f2.glb.mon.snc.tavg-u-hxy-lnd.gn.v20190406 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gn_UKESM1-1-LL_r1i1p1f2__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.MOHC.UKESM1-1-LL.historical.r1i1p1f2.glb.mon.snc.tavg-u-hxy-lnd.gn.v20220512 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gr1_GFDL-CM4_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.NOAA-GFDL.GFDL-CM4.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr1.v20180701 - CMIP7.CMIP.NOAA-GFDL.GFDL-CM4.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr1.v20180701 - CMIP7.CMIP.NOAA-GFDL.GFDL-CM4.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gr1.v20180701 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gr1_GFDL-ESM4_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr1.v20190726 - CMIP7.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr1.v20190726 - CMIP7.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gr1.v20180701 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gr_CIESM_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.THU.CIESM.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gr.v20200417 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gr_CNRM-CM6-1-HR_r1i1p1f2__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1-HR.historical.r1i1p1f2.glb.fx.areacella.ti-u-hxy-u.gr.v20191021 - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1-HR.historical.r1i1p1f2.glb.fx.sftlf.ti-u-hxy-u.gr.v20191021 - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1-HR.historical.r1i1p1f2.glb.mon.snc.tavg-u-hxy-lnd.gr.v20191021 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gr_CNRM-CM6-1_r1i1p1f2__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.glb.fx.areacella.ti-u-hxy-u.gr.v20180917 - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.glb.fx.sftlf.ti-u-hxy-u.gr.v20180917 - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.glb.mon.snc.tavg-u-hxy-lnd.gr.v20180917 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gr_CNRM-ESM2-1_r1i1p1f2__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r13i1p1f2.glb.fx.areacella.ti-u-hxy-u.gr.v20250328 - CMIP7.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.glb.mon.snc.tavg-u-hxy-lnd.gr.v20181206 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gr_EC-Earth3-AerChem_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-AerChem.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20200624 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-AerChem.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20200624 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-AerChem.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gr.v20200624 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gr_EC-Earth3-CC_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20210616 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gr.v20210113 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gr_EC-Earth3-Veg-LR_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20200217 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20200217 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gr.v20200217 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gr_EC-Earth3-Veg_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r11i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20230203 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20211207 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gr.v20211207 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gr_EC-Earth3_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20210324 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20200310 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gr.v20200310 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gr_GISS-E3-G_r1i1p101f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.glb.fx.areacella.ti-u-hxy-u.gr.v20230320 - CMIP7.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20230320 - CMIP7.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.glb.mon.snc.tavg-u-hxy-lnd.gr.v20230320 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gr_IPSL-CM5A2-INCA_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.IPSL.IPSL-CM5A2-INCA.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20200729 - CMIP7.CMIP.IPSL.IPSL-CM5A2-INCA.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gr.v20200729 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gr_IPSL-CM6A-LR-INCA_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.IPSL.IPSL-CM6A-LR-INCA.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gr.v20210216 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 cmip7_historical_gr_IPSL-CM6A-LR_r1i1p1f1__obs4mips_gn_CCI-CryoClim-FSC-1_snc_v20250519: cmip7: - CMIP7.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.glb.fx.areacella.ti-u-hxy-u.gr.v20180803 - CMIP7.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.glb.fx.sftlf.ti-u-hxy-u.gr.v20180803 - CMIP7.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.glb.mon.snc.tavg-u-hxy-lnd.gr.v20180803 obs4mips: - - obs4MIPs.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 + - obs4REF.obs4REF.ESACCI.CCI-CryoClim-FSC-1.mon.snc.0.5x0.5degree.gn.v20250519 diff --git a/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_so_woa2023_surface_.yml b/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_so_woa2023_surface_.yml index 726dc1489..bfe0b92e0 100644 --- a/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_so_woa2023_surface_.yml +++ b/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_so_woa2023_surface_.yml @@ -4,923 +4,923 @@ cmip6_historical_gn_r1i1p101f1_GISS-E3-G__obs4mips_gn_WOA-23_so_v20251024: - CMIP6.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.Ofx.sftof.gn.v20230320 - CMIP6.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.Omon.sos.gn.v20230320 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_ACCESS-CM2__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.CSIRO-ARCCSS.ACCESS-CM2.historical.r1i1p1f1.Ofx.areacello.gn.v20191108 - CMIP6.CMIP.CSIRO-ARCCSS.ACCESS-CM2.historical.r1i1p1f1.Ofx.sftof.gn.v20191108 - CMIP6.CMIP.CSIRO-ARCCSS.ACCESS-CM2.historical.r1i1p1f1.Omon.sos.gn.v20191108 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_ACCESS-ESM1-5__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Ofx.areacello.gn.v20191115 - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Ofx.sftof.gn.v20191115 - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Omon.sos.gn.v20191115 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_AWI-CM-1-1-MR__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.AWI.AWI-CM-1-1-MR.historical.r1i1p1f1.Ofx.areacello.gn.v20181218 - CMIP6.CMIP.AWI.AWI-CM-1-1-MR.historical.r1i1p1f1.Omon.sos.gn.v20181218 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_AWI-ESM-1-1-LR__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.Omon.sos.gn.v20200212 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_BCC-CSM2-MR__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.BCC.BCC-CSM2-MR.historical.r1i1p1f1.Omon.sos.gn.v20181126 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_BCC-ESM1__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.BCC.BCC-ESM1.historical.r1i1p1f1.Omon.sos.gn.v20181129 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_CAS-ESM2-0__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.CAS.CAS-ESM2-0.historical.r1i1p1f1.Ofx.areacello.gn.v20201228 - CMIP6.CMIP.CAS.CAS-ESM2-0.historical.r1i1p1f1.Ofx.volcello.gn.v20201228 - CMIP6.CMIP.CAS.CAS-ESM2-0.historical.r1i1p1f1.Omon.sos.gn.v20201228 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_CESM2-FV2__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.Ofx.areacello.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.Ofx.sftof.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.Omon.sos.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_CESM2-WACCM-FV2__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.Ofx.areacello.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.Ofx.sftof.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.Omon.sos.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_CESM2-WACCM__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.Ofx.sftof.gn.v20190227 - CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.Omon.sos.gn.v20190808 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_CESM2__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Ofx.areacello.gn.v20190308 - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Ofx.sftof.gn.v20190308 - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Omon.sos.gn.v20190308 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_CMCC-CM2-HR4__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.CMCC.CMCC-CM2-HR4.historical.r1i1p1f1.Ofx.areacello.gn.v20200904 - CMIP6.CMIP.CMCC.CMCC-CM2-HR4.historical.r1i1p1f1.Ofx.volcello.gn.v20200904 - CMIP6.CMIP.CMCC.CMCC-CM2-HR4.historical.r1i1p1f1.Omon.sos.gn.v20200904 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_CMCC-CM2-SR5__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.Ofx.areacello.gn.v20200616 - CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.Ofx.sftof.gn.v20220720 - CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.Omon.sos.gn.v20200616 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_CMCC-ESM2__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.Ofx.areacello.gn.v20210114 - CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.Ofx.sftof.gn.v20220720 - CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.Omon.sos.gn.v20210114 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_CanESM5-1__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.Ofx.areacello.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.Ofx.volcello.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.Omon.sos.gn.v20190429 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_CanESM5__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.Ofx.areacello.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.Ofx.sftof.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.Omon.sos.gn.v20190429 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_EC-Earth3-AerChem__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-AerChem.historical.r1i1p1f1.Ofx.areacello.gn.v20200624 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-AerChem.historical.r1i1p1f1.Ofx.sftof.gn.v20200624 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-AerChem.historical.r1i1p1f1.Omon.sos.gn.v20200624 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_EC-Earth3-CC__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.Ofx.areacello.gn.v20210113 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.Ofx.sftof.gn.v20220407 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.Omon.sos.gn.v20210113 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_EC-Earth3-Veg-LR__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.Ofx.areacello.gn.v20200919 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.Ofx.sftof.gn.v20200919 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.Omon.sos.gn.v20200919 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_EC-Earth3-Veg__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.Ofx.areacello.gn.v20211207 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.Ofx.sftof.gn.v20211207 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.Omon.sos.gn.v20211207 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_EC-Earth3__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r1i1p1f1.Ofx.areacello.gn.v20200918 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r1i1p1f1.Ofx.sftof.gn.v20200918 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r1i1p1f1.Omon.sos.gn.v20200918 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_FGOALS-g3__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.Ofx.areacello.gn.v20200917 - CMIP6.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.Ofx.volcello.gn.v20200917 - CMIP6.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.Omon.sos.gn.v20191107 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_GFDL-CM4__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.NOAA-GFDL.GFDL-CM4.historical.r1i1p1f1.Ofx.areacello.gn.v20180701 - CMIP6.CMIP.NOAA-GFDL.GFDL-CM4.historical.r1i1p1f1.Omon.sos.gn.v20180701 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_GFDL-ESM4__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.Ofx.areacello.gn.v20190726 - CMIP6.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.Omon.sos.gn.v20190726 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_GISS-E2-1-G-CC__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-1-G-CC.historical.r1i1p1f1.Omon.sos.gn.v20190815 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_GISS-E2-1-G__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-1-G.historical.r1i1p1f1.Omon.sos.gn.v20180827 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_GISS-E2-1-H__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-1-H.historical.r1i1p1f1.Omon.sos.gn.v20190403 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_GISS-E2-2-G__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-2-G.historical.r1i1p1f1.Omon.sos.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_GISS-E2-2-H__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-2-H.historical.r1i1p1f1.Omon.sos.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_ICON-ESM-LR__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.Ofx.areacello.gn.v20210215 - CMIP6.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.Omon.sos.gn.v20210215 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_IITM-ESM__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.CCCR-IITM.IITM-ESM.historical.r1i1p1f1.Omon.sos.gn.v20200915 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_IPSL-CM5A2-INCA__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.IPSL.IPSL-CM5A2-INCA.historical.r1i1p1f1.Ofx.areacello.gn.v20200729 - CMIP6.CMIP.IPSL.IPSL-CM5A2-INCA.historical.r1i1p1f1.Omon.sos.gn.v20200729 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_IPSL-CM6A-LR-INCA__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.IPSL.IPSL-CM6A-LR-INCA.historical.r1i1p1f1.Ofx.areacello.gn.v20210216 - CMIP6.CMIP.IPSL.IPSL-CM6A-LR-INCA.historical.r1i1p1f1.Omon.sos.gn.v20210216 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_IPSL-CM6A-LR__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.Ofx.areacello.gn.v20180803 - CMIP6.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.Omon.sos.gn.v20180803 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_MCM-UA-1-0__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.UA.MCM-UA-1-0.historical.r1i1p1f1.Ofx.areacello.gn.v20190731 - CMIP6.CMIP.UA.MCM-UA-1-0.historical.r1i1p1f1.Omon.sos.gn.v20190731 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_MIROC6__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.MIROC.MIROC6.historical.r1i1p1f1.Ofx.areacello.gn.v20190311 - CMIP6.CMIP.MIROC.MIROC6.historical.r1i1p1f1.Ofx.sftof.gn.v20190311 - CMIP6.CMIP.MIROC.MIROC6.historical.r1i1p1f1.Omon.sos.gn.v20181212 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_MPI-ESM-1-2-HAM__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.Ofx.areacello.gn.v20190627 - CMIP6.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.Ofx.sftof.gn.v20190627 - CMIP6.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.Omon.sos.gn.v20190627 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_MPI-ESM1-2-HR__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.Ofx.areacello.gn.v20190710 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.Ofx.sftof.gn.v20190710 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.Omon.sos.gn.v20190710 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_MPI-ESM1-2-LR__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.Ofx.areacello.gn.v20190710 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.Ofx.sftof.gn.v20190710 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.Omon.sos.gn.v20190710 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_MRI-ESM2-0__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.Ofx.areacello.gn.v20191210 - CMIP6.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.Ofx.sftof.gn.v20191210 - CMIP6.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.Omon.sos.gn.v20210311 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_NESM3__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.NUIST.NESM3.historical.r1i1p1f1.Omon.sos.gn.v20190703 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_NorCPM1__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.NCC.NorCPM1.historical.r1i1p1f1.Ofx.areacello.gn.v20200724 - CMIP6.CMIP.NCC.NorCPM1.historical.r1i1p1f1.Ofx.sftof.gn.v20200724 - CMIP6.CMIP.NCC.NorCPM1.historical.r1i1p1f1.Omon.sos.gn.v20200724 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_NorESM2-MM__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.Ofx.areacello.gn.v20191108 - CMIP6.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.Ofx.sftof.gn.v20191108 - CMIP6.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.Omon.sos.gn.v20191108 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_SAM0-UNICON__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.Ofx.areacello.gn.v20190323 - CMIP6.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.Omon.sos.gn.v20190323 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f2_CNRM-CM6-1-HR__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1-HR.historical.r1i1p1f2.Ofx.areacello.gn.v20191021 - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1-HR.historical.r1i1p1f2.Omon.sos.gn.v20191021 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f2_CNRM-CM6-1__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.Ofx.areacello.gn.v20180917 - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.Omon.sos.gn.v20180917 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f2_CNRM-ESM2-1__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.Ofx.areacello.gn.v20181206 - CMIP6.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.Omon.sos.gn.v20181206 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f2_MIROC-ES2L__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.Ofx.areacello.gn.v20190823 - CMIP6.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.Ofx.sftof.gn.v20190823 - CMIP6.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.Omon.sos.gn.v20190823 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f2_UKESM1-0-LL__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.MOHC.UKESM1-0-LL.historical.r1i1p1f2.Omon.sos.gn.v20190627 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f2_UKESM1-1-LL__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.MOHC.UKESM1-1-LL.historical.r1i1p1f2.Omon.sos.gn.v20220512 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f3_HadGEM3-GC31-LL__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.MOHC.HadGEM3-GC31-LL.historical.r1i1p1f3.Omon.sos.gn.v20190624 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f3_HadGEM3-GC31-MM__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.MOHC.HadGEM3-GC31-MM.historical.r1i1p1f3.Omon.sos.gn.v20191207 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p2f1_CanESM5-CanOE__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.Ofx.areacello.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.Ofx.sftof.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.Omon.sos.gn.v20190429 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p4f2_MIROC-ES2H__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.MIROC.MIROC-ES2H.historical.r1i1p4f2.Ofx.areacello.gn.v20220322 - CMIP6.CMIP.MIROC.MIROC-ES2H.historical.r1i1p4f2.Ofx.sftof.gn.v20220322 - CMIP6.CMIP.MIROC.MIROC-ES2H.historical.r1i1p4f2.Omon.sos.gn.v20220322 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gr1_r1i1p1f1_INM-CM4-8__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.INM.INM-CM4-8.historical.r1i1p1f1.Omon.sos.gr1.v20190530 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gr1_r1i1p1f1_INM-CM5-0__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.INM.INM-CM5-0.historical.r1i1p1f1.Omon.sos.gr1.v20190610 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gr1_r1i1p1f1_KIOST-ESM__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.KIOST.KIOST-ESM.historical.r1i1p1f1.Ofx.areacello.gr1.v20210601 - CMIP6.CMIP.KIOST.KIOST-ESM.historical.r1i1p1f1.Omon.sos.gr1.v20220204 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gr1_r1i1p1f2_CNRM-CM6-1__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.Omon.sos.gr1.v20180917 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gr1_r1i1p1f2_CNRM-ESM2-1__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.Omon.sos.gr1.v20181206 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gr1_r1i1p1f2_MIROC-ES2L__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.Omon.sos.gr1.v20200731 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gr1_r1i1p4f2_MIROC-ES2H__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.MIROC.MIROC-ES2H.historical.r1i1p4f2.Omon.sos.gr1.v20230904 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gr_r12i1p1f1_EC-Earth3-Veg__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r12i1p1f1.Omon.sos.gr.v20200925 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_CESM2-FV2__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.Ofx.areacello.gr.v20191120 - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.Omon.sos.gr.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_CESM2-WACCM-FV2__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.Ofx.areacello.gr.v20191120 - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.Omon.sos.gr.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_CESM2-WACCM__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.Omon.sos.gr.v20190808 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_CESM2__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Ofx.areacello.gr.v20190308 - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Omon.sos.gr.v20190308 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_E3SM-1-0__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.E3SM-Project.E3SM-1-0.historical.r1i1p1f1.Ofx.areacello.gr.v20210127 - CMIP6.CMIP.E3SM-Project.E3SM-1-0.historical.r1i1p1f1.Omon.sos.gr.v20190826 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_E3SM-1-1-ECA__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.E3SM-Project.E3SM-1-1-ECA.historical.r1i1p1f1.Omon.sos.gr.v20200127 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_E3SM-1-1__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.E3SM-Project.E3SM-1-1.historical.r1i1p1f1.Omon.sos.gr.v20191204 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_E3SM-2-0-NARRM__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.E3SM-Project.E3SM-2-0-NARRM.historical.r1i1p1f1.Ofx.areacello.gr.v20231010 - CMIP6.CMIP.E3SM-Project.E3SM-2-0-NARRM.historical.r1i1p1f1.Omon.sos.gr.v20230509 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_E3SM-2-0__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.E3SM-Project.E3SM-2-0.historical.r1i1p1f1.Ofx.areacello.gr.v20231010 - CMIP6.CMIP.E3SM-Project.E3SM-2-0.historical.r1i1p1f1.Omon.sos.gr.v20221112 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_E3SM-2-1__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.E3SM-Project.E3SM-2-1.historical.r1i1p1f1.Ofx.areacello.gr.v20240209 - CMIP6.CMIP.E3SM-Project.E3SM-2-1.historical.r1i1p1f1.Omon.sos.gr.v20240210 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_GFDL-CM4__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.NOAA-GFDL.GFDL-CM4.historical.r1i1p1f1.Omon.sos.gr.v20180701 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_GFDL-ESM4__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.Ofx.areacello.gr.v20190726 - CMIP6.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.Omon.sos.gr.v20190726 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_KACE-1-0-G__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.NIMS-KMA.KACE-1-0-G.historical.r1i1p1f1.Omon.sos.gr.v20200130 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_MRI-ESM2-0__obs4mips_gn_WOA-23_so_v20251024: cmip6: - CMIP6.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.Omon.sos.gr.v20191205 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_ACCESS-CM2_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.CSIRO-ARCCSS.ACCESS-CM2.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20191108 - CMIP7.CMIP.CSIRO-ARCCSS.ACCESS-CM2.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20191108 - CMIP7.CMIP.CSIRO-ARCCSS.ACCESS-CM2.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20191108 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_ACCESS-ESM1-5_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20191115 - CMIP7.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20191115 - CMIP7.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20191115 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_AWI-CM-1-1-MR_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.AWI.AWI-CM-1-1-MR.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20181218 - CMIP7.CMIP.AWI.AWI-CM-1-1-MR.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20181218 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_AWI-ESM-1-1-LR_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20200212 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_BCC-CSM2-MR_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.BCC.BCC-CSM2-MR.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20181126 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_BCC-ESM1_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.BCC.BCC-ESM1.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20181129 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_CAS-ESM2-0_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.CAS.CAS-ESM2-0.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20201228 - CMIP7.CMIP.CAS.CAS-ESM2-0.historical.r1i1p1f1.glb.fx.volcello.ti-ol-hxy-sea.gn.v20201228 - CMIP7.CMIP.CAS.CAS-ESM2-0.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20201228 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_CESM2-FV2_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_CESM2-WACCM-FV2_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_CESM2-WACCM_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20190227 - CMIP7.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20190808 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_CESM2_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20190308 - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20190308 - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20190308 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_CMCC-CM2-HR4_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.CMCC.CMCC-CM2-HR4.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20200904 - CMIP7.CMIP.CMCC.CMCC-CM2-HR4.historical.r1i1p1f1.glb.fx.volcello.ti-ol-hxy-sea.gn.v20200904 - CMIP7.CMIP.CMCC.CMCC-CM2-HR4.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20200904 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_CMCC-CM2-SR5_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20200616 - CMIP7.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20220720 - CMIP7.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20200616 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_CMCC-ESM2_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20210114 - CMIP7.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20220720 - CMIP7.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20210114 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_CNRM-CM6-1-HR_r1i1p1f2__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1-HR.historical.r1i1p1f2.glb.fx.areacello.ti-u-hxy-u.gn.v20191021 - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1-HR.historical.r1i1p1f2.glb.mon.sos.tavg-u-hxy-sea.gn.v20191021 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_CNRM-CM6-1_r1i1p1f2__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.glb.fx.areacello.ti-u-hxy-u.gn.v20180917 - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.glb.mon.sos.tavg-u-hxy-sea.gn.v20180917 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_CNRM-ESM2-1_r1i1p1f2__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.glb.fx.areacello.ti-u-hxy-u.gn.v20181206 - CMIP7.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.glb.mon.sos.tavg-u-hxy-sea.gn.v20181206 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_CanESM5-1_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.glb.fx.volcello.ti-ol-hxy-sea.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20190429 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_CanESM5-CanOE_r1i1p2f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.glb.fx.areacello.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.glb.fx.sftof.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20190429 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_CanESM5_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.CCCma.CanESM5.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20190429 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_EC-Earth3-AerChem_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-AerChem.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20200624 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-AerChem.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20200624 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-AerChem.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20200624 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_EC-Earth3-CC_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20210113 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20220407 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20210113 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_EC-Earth3-Veg-LR_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20200919 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20200919 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20200919 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_EC-Earth3-Veg_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20211207 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20211207 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20211207 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_EC-Earth3_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20200918 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20200918 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20200918 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_FGOALS-g3_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20200917 - CMIP7.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.glb.fx.volcello.ti-ol-hxy-sea.gn.v20200917 - CMIP7.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20191107 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_GFDL-CM4_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.NOAA-GFDL.GFDL-CM4.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20180701 - CMIP7.CMIP.NOAA-GFDL.GFDL-CM4.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20180701 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_GFDL-ESM4_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20190726 - CMIP7.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20190726 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_GISS-E2-1-G-CC_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-1-G-CC.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20190815 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_GISS-E2-1-G_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-1-G.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20180827 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_GISS-E2-1-H_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-1-H.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20190403 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_GISS-E2-2-G_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-2-G.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_GISS-E2-2-H_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-2-H.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_GISS-E3-G_r1i1p101f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.glb.fx.areacello.ti-u-hxy-u.gn.v20230320 - CMIP7.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.glb.fx.sftof.ti-u-hxy-u.gn.v20230320 - CMIP7.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20230320 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_HadGEM3-GC31-LL_r1i1p1f3__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.MOHC.HadGEM3-GC31-LL.historical.r1i1p1f3.glb.mon.sos.tavg-u-hxy-sea.gn.v20190624 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_HadGEM3-GC31-MM_r1i1p1f3__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.MOHC.HadGEM3-GC31-MM.historical.r1i1p1f3.glb.mon.sos.tavg-u-hxy-sea.gn.v20191207 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_ICON-ESM-LR_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20210215 - CMIP7.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20210215 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_IITM-ESM_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.CCCR-IITM.IITM-ESM.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20200915 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_IPSL-CM5A2-INCA_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.IPSL.IPSL-CM5A2-INCA.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20200729 - CMIP7.CMIP.IPSL.IPSL-CM5A2-INCA.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20200729 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_IPSL-CM6A-LR-INCA_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.IPSL.IPSL-CM6A-LR-INCA.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20210216 - CMIP7.CMIP.IPSL.IPSL-CM6A-LR-INCA.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20210216 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_IPSL-CM6A-LR_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20180803 - CMIP7.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20180803 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_MCM-UA-1-0_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.UA.MCM-UA-1-0.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20190731 - CMIP7.CMIP.UA.MCM-UA-1-0.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20190731 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_MIROC-ES2H_r1i1p4f2__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.MIROC.MIROC-ES2H.historical.r1i1p4f2.glb.fx.areacello.ti-u-hxy-u.gn.v20220322 - CMIP7.CMIP.MIROC.MIROC-ES2H.historical.r1i1p4f2.glb.fx.sftof.ti-u-hxy-u.gn.v20220322 - CMIP7.CMIP.MIROC.MIROC-ES2H.historical.r1i1p4f2.glb.mon.sos.tavg-u-hxy-sea.gn.v20220322 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_MIROC-ES2L_r1i1p1f2__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.glb.fx.areacello.ti-u-hxy-u.gn.v20190823 - CMIP7.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.glb.fx.sftof.ti-u-hxy-u.gn.v20190823 - CMIP7.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.glb.mon.sos.tavg-u-hxy-sea.gn.v20190823 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_MIROC6_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.MIROC.MIROC6.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20190311 - CMIP7.CMIP.MIROC.MIROC6.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20190311 - CMIP7.CMIP.MIROC.MIROC6.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20181212 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_MPI-ESM-1-2-HAM_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20190627 - CMIP7.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20190627 - CMIP7.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20190627 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_MPI-ESM1-2-HR_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20190710 - CMIP7.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20190710 - CMIP7.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20190710 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_MPI-ESM1-2-LR_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20190710 - CMIP7.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20190710 - CMIP7.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20190710 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_MRI-ESM2-0_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20191210 - CMIP7.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20191210 - CMIP7.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20210311 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_NESM3_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.NUIST.NESM3.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20190703 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_NorCPM1_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.NCC.NorCPM1.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20200724 - CMIP7.CMIP.NCC.NorCPM1.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20200724 - CMIP7.CMIP.NCC.NorCPM1.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20200724 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_NorESM2-MM_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20191108 - CMIP7.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20191108 - CMIP7.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20191108 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_SAM0-UNICON_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20190323 - CMIP7.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gn.v20190323 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_UKESM1-0-LL_r1i1p1f2__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.MOHC.UKESM1-0-LL.historical.r1i1p1f2.glb.mon.sos.tavg-u-hxy-sea.gn.v20190627 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gn_UKESM1-1-LL_r1i1p1f2__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.MOHC.UKESM1-1-LL.historical.r1i1p1f2.glb.mon.sos.tavg-u-hxy-sea.gn.v20220512 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gr1_CNRM-CM6-1_r1i1p1f2__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.glb.mon.sos.tavg-u-hxy-sea.gr1.v20180917 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gr1_CNRM-ESM2-1_r1i1p1f2__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.glb.mon.sos.tavg-u-hxy-sea.gr1.v20181206 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gr1_INM-CM4-8_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.INM.INM-CM4-8.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gr1.v20190530 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gr1_INM-CM5-0_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.INM.INM-CM5-0.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gr1.v20190610 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gr1_KIOST-ESM_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.KIOST.KIOST-ESM.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gr1.v20210601 - CMIP7.CMIP.KIOST.KIOST-ESM.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gr1.v20220204 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gr1_MIROC-ES2H_r1i1p4f2__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.MIROC.MIROC-ES2H.historical.r1i1p4f2.glb.mon.sos.tavg-u-hxy-sea.gr1.v20230904 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gr1_MIROC-ES2L_r1i1p1f2__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.glb.mon.sos.tavg-u-hxy-sea.gr1.v20200731 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gr_CESM2-FV2_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gr.v20191120 - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gr.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gr_CESM2-WACCM-FV2_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gr.v20191120 - CMIP7.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gr.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gr_CESM2-WACCM_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gr.v20190808 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gr_CESM2_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gr.v20190308 - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gr.v20190308 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gr_E3SM-1-0_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.E3SM-Project.E3SM-1-0.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gr.v20210127 - CMIP7.CMIP.E3SM-Project.E3SM-1-0.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gr.v20190826 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gr_E3SM-1-1-ECA_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.E3SM-Project.E3SM-1-1-ECA.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gr.v20200127 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gr_E3SM-1-1_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.E3SM-Project.E3SM-1-1.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gr.v20191204 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gr_E3SM-2-0-NARRM_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.E3SM-Project.E3SM-2-0-NARRM.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gr.v20231010 - CMIP7.CMIP.E3SM-Project.E3SM-2-0-NARRM.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gr.v20230509 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gr_E3SM-2-0_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.E3SM-Project.E3SM-2-0.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gr.v20231010 - CMIP7.CMIP.E3SM-Project.E3SM-2-0.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gr.v20221112 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gr_E3SM-2-1_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.E3SM-Project.E3SM-2-1.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gr.v20240209 - CMIP7.CMIP.E3SM-Project.E3SM-2-1.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gr.v20240210 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gr_EC-Earth3-Veg_r12i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r12i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gr.v20200925 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gr_GFDL-CM4_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.NOAA-GFDL.GFDL-CM4.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gr.v20180701 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gr_GFDL-ESM4_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gr.v20190726 - CMIP7.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gr.v20190726 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gr_KACE-1-0-G_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.NIMS-KMA.KACE-1-0-G.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gr.v20200130 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 cmip7_historical_gr_MRI-ESM2-0_r1i1p1f1__obs4mips_gn_WOA-23_so_v20251024: cmip7: - CMIP7.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.glb.mon.sos.tavg-u-hxy-sea.gr.v20191205 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.so.1x1degree.gn.v20251024 diff --git a/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_thetao_woa2023_surface_.yml b/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_thetao_woa2023_surface_.yml index c821d0a6a..1d68ad23b 100644 --- a/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_thetao_woa2023_surface_.yml +++ b/packages/climate-ref-ilamb/tests/unit/test_solve_regression/test_solve_regression_thetao_woa2023_surface_.yml @@ -4,52 +4,52 @@ cmip6_historical_gn_r1i1p101f1_GISS-E3-G__obs4mips_gn_WOA-23_thetao_v20251024: - CMIP6.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.Ofx.sftof.gn.v20230320 - CMIP6.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.Omon.tos.gn.v20230320 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_ACCESS-CM2__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.CSIRO-ARCCSS.ACCESS-CM2.historical.r1i1p1f1.Ofx.areacello.gn.v20191108 - CMIP6.CMIP.CSIRO-ARCCSS.ACCESS-CM2.historical.r1i1p1f1.Ofx.sftof.gn.v20191108 - CMIP6.CMIP.CSIRO-ARCCSS.ACCESS-CM2.historical.r1i1p1f1.Omon.tos.gn.v20191108 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_ACCESS-ESM1-5__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Ofx.areacello.gn.v20191115 - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Ofx.sftof.gn.v20191115 - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Omon.tos.gn.v20191115 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_AWI-CM-1-1-MR__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.AWI.AWI-CM-1-1-MR.historical.r1i1p1f1.Ofx.areacello.gn.v20181218 - CMIP6.CMIP.AWI.AWI-CM-1-1-MR.historical.r1i1p1f1.Omon.thetao.gn.v20181218 - CMIP6.CMIP.AWI.AWI-CM-1-1-MR.historical.r1i1p1f1.Omon.tos.gn.v20181218 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_AWI-ESM-1-1-LR__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.Omon.thetao.gn.v20200212 - CMIP6.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.Omon.tos.gn.v20200212 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_BCC-CSM2-MR__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.BCC.BCC-CSM2-MR.historical.r1i1p1f1.Omon.thetao.gn.v20181126 - CMIP6.CMIP.BCC.BCC-CSM2-MR.historical.r1i1p1f1.Omon.tos.gn.v20181126 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_BCC-ESM1__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.BCC.BCC-ESM1.historical.r1i1p1f1.Omon.thetao.gn.v20181129 - CMIP6.CMIP.BCC.BCC-ESM1.historical.r1i1p1f1.Omon.tos.gn.v20181129 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_CAMS-CSM1-0__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.CAMS.CAMS-CSM1-0.historical.r1i1p1f1.Omon.thetao.gn.v20190708 - CMIP6.CMIP.CAMS.CAMS-CSM1-0.historical.r1i1p1f1.Omon.tos.gn.v20190708 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_CAS-ESM2-0__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.CAS.CAS-ESM2-0.historical.r1i1p1f1.Ofx.areacello.gn.v20201228 @@ -57,62 +57,62 @@ cmip6_historical_gn_r1i1p1f1_CAS-ESM2-0__obs4mips_gn_WOA-23_thetao_v20251024: - CMIP6.CMIP.CAS.CAS-ESM2-0.historical.r1i1p1f1.Omon.thetao.gn.v20201228 - CMIP6.CMIP.CAS.CAS-ESM2-0.historical.r1i1p1f1.Omon.tos.gn.v20201228 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_CESM2-FV2__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.Ofx.areacello.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.Ofx.sftof.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.Omon.tos.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_CESM2-WACCM-FV2__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.Ofx.areacello.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.Ofx.sftof.gn.v20191120 - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.Omon.tos.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_CESM2-WACCM__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.Ofx.sftof.gn.v20190227 - CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.Omon.tos.gn.v20190808 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_CESM2__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Ofx.areacello.gn.v20190308 - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Ofx.sftof.gn.v20190308 - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Omon.tos.gn.v20190308 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_CIESM__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.THU.CIESM.historical.r1i1p1f1.Ofx.areacello.gn.v20200220 - CMIP6.CMIP.THU.CIESM.historical.r1i1p1f1.Ofx.sftof.gn.v20200220 - CMIP6.CMIP.THU.CIESM.historical.r1i1p1f1.Omon.tos.gn.v20200220 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_CMCC-CM2-HR4__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.CMCC.CMCC-CM2-HR4.historical.r1i1p1f1.Ofx.areacello.gn.v20200904 - CMIP6.CMIP.CMCC.CMCC-CM2-HR4.historical.r1i1p1f1.Ofx.volcello.gn.v20200904 - CMIP6.CMIP.CMCC.CMCC-CM2-HR4.historical.r1i1p1f1.Omon.tos.gn.v20200904 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_CMCC-CM2-SR5__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.Ofx.areacello.gn.v20200616 - CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.Ofx.sftof.gn.v20220720 - CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.Omon.tos.gn.v20200616 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_CMCC-ESM2__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.Ofx.areacello.gn.v20210114 - CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.Ofx.sftof.gn.v20220720 - CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.Omon.tos.gn.v20210114 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_CanESM5-1__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.Ofx.areacello.gn.v20190429 @@ -120,7 +120,7 @@ cmip6_historical_gn_r1i1p1f1_CanESM5-1__obs4mips_gn_WOA-23_thetao_v20251024: - CMIP6.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.Omon.thetao.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.Omon.tos.gn.v20190429 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_CanESM5__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.Ofx.areacello.gn.v20190429 @@ -128,42 +128,42 @@ cmip6_historical_gn_r1i1p1f1_CanESM5__obs4mips_gn_WOA-23_thetao_v20251024: - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.Omon.thetao.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.Omon.tos.gn.v20190429 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_EC-Earth3-AerChem__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-AerChem.historical.r1i1p1f1.Ofx.areacello.gn.v20200624 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-AerChem.historical.r1i1p1f1.Ofx.sftof.gn.v20200624 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-AerChem.historical.r1i1p1f1.Omon.tos.gn.v20200624 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_EC-Earth3-CC__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.Ofx.areacello.gn.v20210113 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.Ofx.sftof.gn.v20220407 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.Omon.tos.gn.v20210113 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_EC-Earth3-Veg-LR__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.Ofx.areacello.gn.v20200919 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.Ofx.sftof.gn.v20200919 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.Omon.tos.gn.v20200919 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_EC-Earth3-Veg__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.Ofx.areacello.gn.v20211207 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.Ofx.sftof.gn.v20211207 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.Omon.tos.gn.v20211207 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_EC-Earth3__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r1i1p1f1.Ofx.areacello.gn.v20200918 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r1i1p1f1.Ofx.sftof.gn.v20200918 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r1i1p1f1.Omon.tos.gn.v20200918 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_FGOALS-f3-L__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.CAS.FGOALS-f3-L.historical.r1i1p1f1.Ofx.areacello.gn.v20190918 @@ -171,7 +171,7 @@ cmip6_historical_gn_r1i1p1f1_FGOALS-f3-L__obs4mips_gn_WOA-23_thetao_v20251024: - CMIP6.CMIP.CAS.FGOALS-f3-L.historical.r1i1p1f1.Omon.thetao.gn.v20191007 - CMIP6.CMIP.CAS.FGOALS-f3-L.historical.r1i1p1f1.Omon.tos.gn.v20191007 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_FGOALS-g3__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.Ofx.areacello.gn.v20200917 @@ -179,152 +179,152 @@ cmip6_historical_gn_r1i1p1f1_FGOALS-g3__obs4mips_gn_WOA-23_thetao_v20251024: - CMIP6.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.Omon.thetao.gn.v20191012 - CMIP6.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.Omon.tos.gn.v20191107 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_FIO-ESM-2-0__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.FIO-QLNM.FIO-ESM-2-0.historical.r1i1p1f1.Ofx.areacello.gn.v20200928 - CMIP6.CMIP.FIO-QLNM.FIO-ESM-2-0.historical.r1i1p1f1.Omon.tos.gn.v20191122 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_GFDL-CM4__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.NOAA-GFDL.GFDL-CM4.historical.r1i1p1f1.Ofx.areacello.gn.v20180701 - CMIP6.CMIP.NOAA-GFDL.GFDL-CM4.historical.r1i1p1f1.Omon.tos.gn.v20180701 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_GFDL-ESM4__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.Ofx.areacello.gn.v20190726 - CMIP6.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.Omon.tos.gn.v20190726 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_GISS-E2-1-G-CC__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-1-G-CC.historical.r1i1p1f1.Omon.tos.gn.v20190815 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_GISS-E2-1-G__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-1-G.historical.r1i1p1f1.Omon.tos.gn.v20180827 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_GISS-E2-1-H__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-1-H.historical.r1i1p1f1.Omon.tos.gn.v20190403 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_GISS-E2-2-G__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-2-G.historical.r1i1p1f1.Omon.tos.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_GISS-E2-2-H__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.NASA-GISS.GISS-E2-2-H.historical.r1i1p1f1.Omon.tos.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_ICON-ESM-LR__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.Ofx.areacello.gn.v20210215 - CMIP6.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.Omon.tos.gn.v20210215 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_IITM-ESM__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.CCCR-IITM.IITM-ESM.historical.r1i1p1f1.Omon.tos.gn.v20200915 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_IPSL-CM5A2-INCA__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.IPSL.IPSL-CM5A2-INCA.historical.r1i1p1f1.Ofx.areacello.gn.v20200729 - CMIP6.CMIP.IPSL.IPSL-CM5A2-INCA.historical.r1i1p1f1.Omon.tos.gn.v20200729 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_IPSL-CM6A-LR-INCA__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.IPSL.IPSL-CM6A-LR-INCA.historical.r1i1p1f1.Ofx.areacello.gn.v20210216 - CMIP6.CMIP.IPSL.IPSL-CM6A-LR-INCA.historical.r1i1p1f1.Omon.tos.gn.v20210216 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_IPSL-CM6A-LR__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.Ofx.areacello.gn.v20180803 - CMIP6.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.Omon.tos.gn.v20180803 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_MCM-UA-1-0__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.UA.MCM-UA-1-0.historical.r1i1p1f1.Ofx.areacello.gn.v20190731 - CMIP6.CMIP.UA.MCM-UA-1-0.historical.r1i1p1f1.Omon.tos.gn.v20190731 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_MIROC6__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.MIROC.MIROC6.historical.r1i1p1f1.Ofx.areacello.gn.v20190311 - CMIP6.CMIP.MIROC.MIROC6.historical.r1i1p1f1.Ofx.sftof.gn.v20190311 - CMIP6.CMIP.MIROC.MIROC6.historical.r1i1p1f1.Omon.tos.gn.v20181212 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_MPI-ESM-1-2-HAM__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.Ofx.areacello.gn.v20190627 - CMIP6.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.Ofx.sftof.gn.v20190627 - CMIP6.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.Omon.tos.gn.v20190627 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_MPI-ESM1-2-HR__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.Ofx.areacello.gn.v20190710 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.Ofx.sftof.gn.v20190710 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.Omon.tos.gn.v20190710 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_MPI-ESM1-2-LR__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.Ofx.areacello.gn.v20190710 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.Ofx.sftof.gn.v20190710 - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.Omon.tos.gn.v20190710 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_MRI-ESM2-0__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.Ofx.areacello.gn.v20191210 - CMIP6.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.Ofx.sftof.gn.v20191210 - CMIP6.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.Omon.tos.gn.v20190904 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_NESM3__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.NUIST.NESM3.historical.r1i1p1f1.Omon.tos.gn.v20190703 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_NorCPM1__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.NCC.NorCPM1.historical.r1i1p1f1.Ofx.areacello.gn.v20200724 - CMIP6.CMIP.NCC.NorCPM1.historical.r1i1p1f1.Ofx.sftof.gn.v20200724 - CMIP6.CMIP.NCC.NorCPM1.historical.r1i1p1f1.Omon.tos.gn.v20200724 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_NorESM2-LM__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.Ofx.areacello.gn.v20190815 - CMIP6.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.Ofx.sftof.gn.v20191108 - CMIP6.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.Omon.tos.gn.v20190815 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_NorESM2-MM__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.Ofx.areacello.gn.v20191108 - CMIP6.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.Ofx.sftof.gn.v20191108 - CMIP6.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.Omon.tos.gn.v20191108 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_SAM0-UNICON__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.Ofx.areacello.gn.v20190323 - CMIP6.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.Omon.tos.gn.v20190323 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f1_TaiESM1__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.Ofx.areacello.gn.v20210212 @@ -332,52 +332,52 @@ cmip6_historical_gn_r1i1p1f1_TaiESM1__obs4mips_gn_WOA-23_thetao_v20251024: - CMIP6.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.Omon.thetao.gn.v20200630 - CMIP6.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.Omon.tos.gn.v20200630 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f2_CNRM-CM6-1-HR__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1-HR.historical.r1i1p1f2.Ofx.areacello.gn.v20191021 - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1-HR.historical.r1i1p1f2.Omon.tos.gn.v20191021 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f2_CNRM-CM6-1__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.Ofx.areacello.gn.v20180917 - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.Omon.tos.gn.v20180917 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f2_CNRM-ESM2-1__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.Ofx.areacello.gn.v20181206 - CMIP6.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.Omon.tos.gn.v20181206 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f2_MIROC-ES2L__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.Ofx.areacello.gn.v20190823 - CMIP6.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.Ofx.sftof.gn.v20190823 - CMIP6.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.Omon.tos.gn.v20190823 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f2_UKESM1-0-LL__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.MOHC.UKESM1-0-LL.historical.r1i1p1f2.Omon.tos.gn.v20190627 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f2_UKESM1-1-LL__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.MOHC.UKESM1-1-LL.historical.r1i1p1f2.Omon.tos.gn.v20220512 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f3_HadGEM3-GC31-LL__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.MOHC.HadGEM3-GC31-LL.historical.r1i1p1f3.Omon.tos.gn.v20190624 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p1f3_HadGEM3-GC31-MM__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.MOHC.HadGEM3-GC31-MM.historical.r1i1p1f3.Omon.tos.gn.v20191207 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p2f1_CanESM5-CanOE__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.Ofx.areacello.gn.v20190429 @@ -385,189 +385,189 @@ cmip6_historical_gn_r1i1p2f1_CanESM5-CanOE__obs4mips_gn_WOA-23_thetao_v20251024: - CMIP6.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.Omon.thetao.gn.v20190429 - CMIP6.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.Omon.tos.gn.v20190429 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gn_r1i1p4f2_MIROC-ES2H__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.MIROC.MIROC-ES2H.historical.r1i1p4f2.Ofx.areacello.gn.v20220322 - CMIP6.CMIP.MIROC.MIROC-ES2H.historical.r1i1p4f2.Ofx.sftof.gn.v20220322 - CMIP6.CMIP.MIROC.MIROC-ES2H.historical.r1i1p4f2.Omon.tos.gn.v20220322 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gr1_r1i1p1f1_INM-CM4-8__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.INM.INM-CM4-8.historical.r1i1p1f1.Omon.tos.gr1.v20190530 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gr1_r1i1p1f1_INM-CM5-0__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.INM.INM-CM5-0.historical.r1i1p1f1.Omon.tos.gr1.v20190610 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gr1_r1i1p1f1_KIOST-ESM__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.KIOST.KIOST-ESM.historical.r1i1p1f1.Ofx.areacello.gr1.v20210601 - CMIP6.CMIP.KIOST.KIOST-ESM.historical.r1i1p1f1.Omon.tos.gr1.v20220204 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gr1_r1i1p1f2_CNRM-CM6-1__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.Omon.tos.gr1.v20180917 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gr1_r1i1p1f2_CNRM-ESM2-1__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.Omon.tos.gr1.v20181206 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gr1_r1i1p1f2_MIROC-ES2L__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.Omon.tos.gr1.v20200731 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gr1_r1i1p4f2_MIROC-ES2H__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.MIROC.MIROC-ES2H.historical.r1i1p4f2.Omon.tos.gr1.v20230904 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gr_r12i1p1f1_EC-Earth3-Veg__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r12i1p1f1.Omon.tos.gr.v20200925 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_CESM2-FV2__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.Ofx.areacello.gr.v20191120 - CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.Omon.tos.gr.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_CESM2-WACCM-FV2__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.Ofx.areacello.gr.v20191120 - CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.Omon.tos.gr.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_CESM2-WACCM__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.Omon.tos.gr.v20190808 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_CESM2__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Ofx.areacello.gr.v20190308 - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Omon.tos.gr.v20190308 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_E3SM-1-0__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.E3SM-Project.E3SM-1-0.historical.r1i1p1f1.Ofx.areacello.gr.v20210127 - CMIP6.CMIP.E3SM-Project.E3SM-1-0.historical.r1i1p1f1.Omon.tos.gr.v20190826 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_E3SM-1-1-ECA__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.E3SM-Project.E3SM-1-1-ECA.historical.r1i1p1f1.Omon.tos.gr.v20200127 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_E3SM-1-1__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.E3SM-Project.E3SM-1-1.historical.r1i1p1f1.Omon.tos.gr.v20191204 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_E3SM-2-0-NARRM__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.E3SM-Project.E3SM-2-0-NARRM.historical.r1i1p1f1.Ofx.areacello.gr.v20231010 - CMIP6.CMIP.E3SM-Project.E3SM-2-0-NARRM.historical.r1i1p1f1.Omon.tos.gr.v20230510 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_E3SM-2-0__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.E3SM-Project.E3SM-2-0.historical.r1i1p1f1.Ofx.areacello.gr.v20231010 - CMIP6.CMIP.E3SM-Project.E3SM-2-0.historical.r1i1p1f1.Omon.tos.gr.v20221112 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_E3SM-2-1__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.E3SM-Project.E3SM-2-1.historical.r1i1p1f1.Ofx.areacello.gr.v20240209 - CMIP6.CMIP.E3SM-Project.E3SM-2-1.historical.r1i1p1f1.Omon.tos.gr.v20240211 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_EC-Earth3-CC__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.Amon.tos.gr.v20210113 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_GFDL-CM4__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.NOAA-GFDL.GFDL-CM4.historical.r1i1p1f1.Omon.tos.gr.v20180701 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_GFDL-ESM4__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.Ofx.areacello.gr.v20190726 - CMIP6.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.Omon.tos.gr.v20190726 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_KACE-1-0-G__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.NIMS-KMA.KACE-1-0-G.historical.r1i1p1f1.Omon.tos.gr.v20200130 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gr_r1i1p1f1_MRI-ESM2-0__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.Omon.tos.gr.v20190904 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip6_historical_gr_r2i1p1f1_EC-Earth3__obs4mips_gn_WOA-23_thetao_v20251024: cmip6: - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r2i1p1f1.Amon.tos.gr.v20201215 - CMIP6.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r2i1p1f1.Omon.tos.gr.v20201215 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_ACCESS-CM2_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.CSIRO-ARCCSS.ACCESS-CM2.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20191108 - CMIP7.CMIP.CSIRO-ARCCSS.ACCESS-CM2.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20191108 - CMIP7.CMIP.CSIRO-ARCCSS.ACCESS-CM2.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20191108 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_ACCESS-ESM1-5_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20191115 - CMIP7.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20191115 - CMIP7.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20191115 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_AWI-CM-1-1-MR_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.AWI.AWI-CM-1-1-MR.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20181218 - CMIP7.CMIP.AWI.AWI-CM-1-1-MR.historical.r1i1p1f1.glb.mon.thetao.tavg-ol-hxy-sea.gn.v20181218 - CMIP7.CMIP.AWI.AWI-CM-1-1-MR.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20181218 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_AWI-ESM-1-1-LR_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.glb.mon.thetao.tavg-ol-hxy-sea.gn.v20200212 - CMIP7.CMIP.AWI.AWI-ESM-1-1-LR.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20200212 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_BCC-CSM2-MR_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.BCC.BCC-CSM2-MR.historical.r1i1p1f1.glb.mon.thetao.tavg-ol-hxy-sea.gn.v20181126 - CMIP7.CMIP.BCC.BCC-CSM2-MR.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20181126 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_BCC-ESM1_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.BCC.BCC-ESM1.historical.r1i1p1f1.glb.mon.thetao.tavg-ol-hxy-sea.gn.v20181129 - CMIP7.CMIP.BCC.BCC-ESM1.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20181129 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_CAMS-CSM1-0_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.CAMS.CAMS-CSM1-0.historical.r1i1p1f1.glb.mon.thetao.tavg-ol-hxy-sea.gn.v20190708 - CMIP7.CMIP.CAMS.CAMS-CSM1-0.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20190708 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_CAS-ESM2-0_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.CAS.CAS-ESM2-0.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20201228 @@ -575,80 +575,80 @@ cmip7_historical_gn_CAS-ESM2-0_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: - CMIP7.CMIP.CAS.CAS-ESM2-0.historical.r1i1p1f1.glb.mon.thetao.tavg-ol-hxy-sea.gn.v20201228 - CMIP7.CMIP.CAS.CAS-ESM2-0.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20201228 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_CESM2-FV2_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_CESM2-WACCM-FV2_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20191120 - CMIP7.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_CESM2-WACCM_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20190227 - CMIP7.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20190808 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_CESM2_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20190308 - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20190308 - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20190308 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_CIESM_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.THU.CIESM.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20200220 - CMIP7.CMIP.THU.CIESM.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20200220 - CMIP7.CMIP.THU.CIESM.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20200220 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_CMCC-CM2-HR4_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.CMCC.CMCC-CM2-HR4.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20200904 - CMIP7.CMIP.CMCC.CMCC-CM2-HR4.historical.r1i1p1f1.glb.fx.volcello.ti-ol-hxy-sea.gn.v20200904 - CMIP7.CMIP.CMCC.CMCC-CM2-HR4.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20200904 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_CMCC-CM2-SR5_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20200616 - CMIP7.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20220720 - CMIP7.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20200616 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_CMCC-ESM2_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20210114 - CMIP7.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20220720 - CMIP7.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20210114 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_CNRM-CM6-1-HR_r1i1p1f2__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1-HR.historical.r1i1p1f2.glb.fx.areacello.ti-u-hxy-u.gn.v20191021 - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1-HR.historical.r1i1p1f2.glb.mon.tos.tavg-u-hxy-sea.gn.v20191021 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_CNRM-CM6-1_r1i1p1f2__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.glb.fx.areacello.ti-u-hxy-u.gn.v20180917 - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.glb.mon.tos.tavg-u-hxy-sea.gn.v20180917 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_CNRM-ESM2-1_r1i1p1f2__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.glb.fx.areacello.ti-u-hxy-u.gn.v20181206 - CMIP7.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.glb.mon.tos.tavg-u-hxy-sea.gn.v20181206 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_CanESM5-1_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20190429 @@ -656,7 +656,7 @@ cmip7_historical_gn_CanESM5-1_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: - CMIP7.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.glb.mon.thetao.tavg-ol-hxy-sea.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5-1.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20190429 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_CanESM5-CanOE_r1i1p2f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.glb.fx.areacello.ti-u-hxy-u.gn.v20190429 @@ -664,7 +664,7 @@ cmip7_historical_gn_CanESM5-CanOE_r1i1p2f1__obs4mips_gn_WOA-23_thetao_v20251024: - CMIP7.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.glb.mon.thetao.tavg-ol-hxy-sea.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5-CanOE.historical.r1i1p2f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20190429 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_CanESM5_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.CCCma.CanESM5.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20190429 @@ -672,42 +672,42 @@ cmip7_historical_gn_CanESM5_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: - CMIP7.CMIP.CCCma.CanESM5.historical.r1i1p1f1.glb.mon.thetao.tavg-ol-hxy-sea.gn.v20190429 - CMIP7.CMIP.CCCma.CanESM5.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20190429 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_EC-Earth3-AerChem_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-AerChem.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20200624 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-AerChem.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20200624 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-AerChem.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20200624 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_EC-Earth3-CC_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20210113 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20220407 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-CC.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20210113 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_EC-Earth3-Veg-LR_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20200919 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20200919 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg-LR.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20200919 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_EC-Earth3-Veg_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20211207 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20211207 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20211207 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_EC-Earth3_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20200918 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20200918 - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20200918 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_FGOALS-f3-L_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.CAS.FGOALS-f3-L.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20190918 @@ -715,7 +715,7 @@ cmip7_historical_gn_FGOALS-f3-L_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: - CMIP7.CMIP.CAS.FGOALS-f3-L.historical.r1i1p1f1.glb.mon.thetao.tavg-ol-hxy-sea.gn.v20191007 - CMIP7.CMIP.CAS.FGOALS-f3-L.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20191007 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_FGOALS-g3_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20200917 @@ -723,183 +723,183 @@ cmip7_historical_gn_FGOALS-g3_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: - CMIP7.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.glb.mon.thetao.tavg-ol-hxy-sea.gn.v20191012 - CMIP7.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20191107 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_FIO-ESM-2-0_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.FIO-QLNM.FIO-ESM-2-0.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20200928 - CMIP7.CMIP.FIO-QLNM.FIO-ESM-2-0.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20191122 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_GFDL-CM4_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.NOAA-GFDL.GFDL-CM4.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20180701 - CMIP7.CMIP.NOAA-GFDL.GFDL-CM4.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20180701 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_GFDL-ESM4_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20190726 - CMIP7.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20190726 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_GISS-E2-1-G-CC_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-1-G-CC.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20190815 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_GISS-E2-1-G_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-1-G.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20180827 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_GISS-E2-1-H_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-1-H.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20190403 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_GISS-E2-2-G_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-2-G.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_GISS-E2-2-H_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E2-2-H.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_GISS-E3-G_r1i1p101f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.glb.fx.areacello.ti-u-hxy-u.gn.v20230320 - CMIP7.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.glb.fx.sftof.ti-u-hxy-u.gn.v20230320 - CMIP7.CMIP.NASA-GISS.GISS-E3-G.historical.r1i1p101f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20230320 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_HadGEM3-GC31-LL_r1i1p1f3__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.MOHC.HadGEM3-GC31-LL.historical.r1i1p1f3.glb.mon.tos.tavg-u-hxy-sea.gn.v20190624 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_HadGEM3-GC31-MM_r1i1p1f3__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.MOHC.HadGEM3-GC31-MM.historical.r1i1p1f3.glb.mon.tos.tavg-u-hxy-sea.gn.v20191207 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_ICON-ESM-LR_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20210215 - CMIP7.CMIP.MPI-M.ICON-ESM-LR.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20210215 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_IITM-ESM_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.CCCR-IITM.IITM-ESM.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20200915 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_IPSL-CM5A2-INCA_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.IPSL.IPSL-CM5A2-INCA.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20200729 - CMIP7.CMIP.IPSL.IPSL-CM5A2-INCA.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20200729 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_IPSL-CM6A-LR-INCA_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.IPSL.IPSL-CM6A-LR-INCA.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20210216 - CMIP7.CMIP.IPSL.IPSL-CM6A-LR-INCA.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20210216 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_IPSL-CM6A-LR_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20180803 - CMIP7.CMIP.IPSL.IPSL-CM6A-LR.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20180803 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_MCM-UA-1-0_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.UA.MCM-UA-1-0.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20190731 - CMIP7.CMIP.UA.MCM-UA-1-0.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20190731 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_MIROC-ES2H_r1i1p4f2__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.MIROC.MIROC-ES2H.historical.r1i1p4f2.glb.fx.areacello.ti-u-hxy-u.gn.v20220322 - CMIP7.CMIP.MIROC.MIROC-ES2H.historical.r1i1p4f2.glb.fx.sftof.ti-u-hxy-u.gn.v20220322 - CMIP7.CMIP.MIROC.MIROC-ES2H.historical.r1i1p4f2.glb.mon.tos.tavg-u-hxy-sea.gn.v20220322 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_MIROC-ES2L_r1i1p1f2__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.glb.fx.areacello.ti-u-hxy-u.gn.v20190823 - CMIP7.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.glb.fx.sftof.ti-u-hxy-u.gn.v20190823 - CMIP7.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.glb.mon.tos.tavg-u-hxy-sea.gn.v20190823 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_MIROC6_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.MIROC.MIROC6.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20190311 - CMIP7.CMIP.MIROC.MIROC6.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20190311 - CMIP7.CMIP.MIROC.MIROC6.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20181212 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_MPI-ESM-1-2-HAM_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20190627 - CMIP7.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20190627 - CMIP7.CMIP.HAMMOZ-Consortium.MPI-ESM-1-2-HAM.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20190627 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_MPI-ESM1-2-HR_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20190710 - CMIP7.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20190710 - CMIP7.CMIP.MPI-M.MPI-ESM1-2-HR.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20190710 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_MPI-ESM1-2-LR_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20190710 - CMIP7.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20190710 - CMIP7.CMIP.MPI-M.MPI-ESM1-2-LR.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20190710 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_MRI-ESM2-0_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20191210 - CMIP7.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20191210 - CMIP7.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20190904 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_NESM3_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.NUIST.NESM3.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20190703 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_NorCPM1_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.NCC.NorCPM1.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20200724 - CMIP7.CMIP.NCC.NorCPM1.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20200724 - CMIP7.CMIP.NCC.NorCPM1.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20200724 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_NorESM2-LM_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20190815 - CMIP7.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20191108 - CMIP7.CMIP.NCC.NorESM2-LM.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20190815 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_NorESM2-MM_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20191108 - CMIP7.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.glb.fx.sftof.ti-u-hxy-u.gn.v20191108 - CMIP7.CMIP.NCC.NorESM2-MM.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20191108 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_SAM0-UNICON_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20190323 - CMIP7.CMIP.SNU.SAM0-UNICON.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20190323 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_TaiESM1_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gn.v20210212 @@ -907,138 +907,138 @@ cmip7_historical_gn_TaiESM1_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: - CMIP7.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.glb.mon.thetao.tavg-ol-hxy-sea.gn.v20200630 - CMIP7.CMIP.AS-RCEC.TaiESM1.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gn.v20200630 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_UKESM1-0-LL_r1i1p1f2__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.MOHC.UKESM1-0-LL.historical.r1i1p1f2.glb.mon.tos.tavg-u-hxy-sea.gn.v20190627 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gn_UKESM1-1-LL_r1i1p1f2__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.MOHC.UKESM1-1-LL.historical.r1i1p1f2.glb.mon.tos.tavg-u-hxy-sea.gn.v20220512 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gr1_CNRM-CM6-1_r1i1p1f2__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.CNRM-CERFACS.CNRM-CM6-1.historical.r1i1p1f2.glb.mon.tos.tavg-u-hxy-sea.gr1.v20180917 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gr1_CNRM-ESM2-1_r1i1p1f2__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.glb.mon.tos.tavg-u-hxy-sea.gr1.v20181206 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gr1_INM-CM4-8_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.INM.INM-CM4-8.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gr1.v20190530 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gr1_INM-CM5-0_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.INM.INM-CM5-0.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gr1.v20190610 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gr1_KIOST-ESM_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.KIOST.KIOST-ESM.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gr1.v20210601 - CMIP7.CMIP.KIOST.KIOST-ESM.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gr1.v20220204 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gr1_MIROC-ES2H_r1i1p4f2__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.MIROC.MIROC-ES2H.historical.r1i1p4f2.glb.mon.tos.tavg-u-hxy-sea.gr1.v20230904 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gr1_MIROC-ES2L_r1i1p1f2__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.MIROC.MIROC-ES2L.historical.r1i1p1f2.glb.mon.tos.tavg-u-hxy-sea.gr1.v20200731 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gr_CESM2-FV2_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gr.v20191120 - CMIP7.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gr.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gr_CESM2-WACCM-FV2_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gr.v20191120 - CMIP7.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gr.v20191120 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gr_CESM2-WACCM_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gr.v20190808 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gr_CESM2_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gr.v20190308 - CMIP7.CMIP.NCAR.CESM2.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gr.v20190308 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gr_E3SM-1-0_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.E3SM-Project.E3SM-1-0.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gr.v20210127 - CMIP7.CMIP.E3SM-Project.E3SM-1-0.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gr.v20190826 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gr_E3SM-1-1-ECA_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.E3SM-Project.E3SM-1-1-ECA.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gr.v20200127 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gr_E3SM-1-1_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.E3SM-Project.E3SM-1-1.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gr.v20191204 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gr_E3SM-2-0-NARRM_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.E3SM-Project.E3SM-2-0-NARRM.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gr.v20231010 - CMIP7.CMIP.E3SM-Project.E3SM-2-0-NARRM.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gr.v20230510 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gr_E3SM-2-0_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.E3SM-Project.E3SM-2-0.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gr.v20231010 - CMIP7.CMIP.E3SM-Project.E3SM-2-0.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gr.v20221112 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gr_E3SM-2-1_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.E3SM-Project.E3SM-2-1.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gr.v20240209 - CMIP7.CMIP.E3SM-Project.E3SM-2-1.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gr.v20240211 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gr_EC-Earth3-Veg_r12i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3-Veg.historical.r12i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gr.v20200925 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gr_EC-Earth3_r2i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.EC-Earth-Consortium.EC-Earth3.historical.r2i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gr.v20201215 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gr_GFDL-CM4_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.NOAA-GFDL.GFDL-CM4.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gr.v20180701 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gr_GFDL-ESM4_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.glb.fx.areacello.ti-u-hxy-u.gr.v20190726 - CMIP7.CMIP.NOAA-GFDL.GFDL-ESM4.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gr.v20190726 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gr_KACE-1-0-G_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.NIMS-KMA.KACE-1-0-G.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gr.v20200130 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 cmip7_historical_gr_MRI-ESM2-0_r1i1p1f1__obs4mips_gn_WOA-23_thetao_v20251024: cmip7: - CMIP7.CMIP.MRI.MRI-ESM2-0.historical.r1i1p1f1.glb.mon.tos.tavg-u-hxy-sea.gr.v20190904 obs4mips: - - obs4MIPs.obs4MIPs.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 + - obs4REF.obs4REF.NOAA-NCEI-OCL.WOA-23.monC.thetao.1x1degree.gn.v20251024 diff --git a/packages/climate-ref-pmp/conftest.py b/packages/climate-ref-pmp/conftest.py index 754bb030b..0bd5b8e09 100644 --- a/packages/climate-ref-pmp/conftest.py +++ b/packages/climate-ref-pmp/conftest.py @@ -18,9 +18,10 @@ def pmp_data_catalog(sample_data_dir) -> pd.DataFrame: @pytest.fixture(scope="session") -def data_catalog(cmip6_data_catalog, obs4mips_data_catalog, pmp_data_catalog): +def data_catalog(cmip6_data_catalog, obs4mips_data_catalog, obs4ref_data_catalog, pmp_data_catalog): return { SourceDatasetType.CMIP6: cmip6_data_catalog, SourceDatasetType.obs4MIPs: obs4mips_data_catalog, + SourceDatasetType.obs4REF: obs4ref_data_catalog, SourceDatasetType.PMPClimatology: pmp_data_catalog, } diff --git a/packages/climate-ref-pmp/src/climate_ref_pmp/__init__.py b/packages/climate-ref-pmp/src/climate_ref_pmp/__init__.py index 18543b265..158a36169 100644 --- a/packages/climate-ref-pmp/src/climate_ref_pmp/__init__.py +++ b/packages/climate-ref-pmp/src/climate_ref_pmp/__init__.py @@ -30,6 +30,18 @@ _REGISTRY_NAME = "pmp-climatology" +_THREAD_LIMIT_VARS = ( + "OMP_NUM_THREADS", + "OPENBLAS_NUM_THREADS", + "MKL_NUM_THREADS", + "NUMEXPR_NUM_THREADS", + "VECLIB_MAXIMUM_THREADS", +) + +# Conservative default for ~10% improvement over a single thread +# Without a default BLAS will take as many CPUs as available +_DEFAULT_THREAD_LIMIT = "2" + # Create the PMP diagnostics provider # PMP uses a conda environment to run the diagnostics @@ -49,6 +61,12 @@ def configure(self, config: Config) -> None: logger.debug("Setting env variable 'FI_PROVIDER=tcp'") self.env_overrides["FI_PROVIDER"] = "tcp" + # If any budgets are set, don't set default values + if not any(name in os.environ for name in _THREAD_LIMIT_VARS): + logger.debug(f"Limiting threads to {_DEFAULT_THREAD_LIMIT}") + for name in _THREAD_LIMIT_VARS: + self.env_overrides[name] = _DEFAULT_THREAD_LIMIT + def fetch_data(self, config: Config) -> None: """Fetch PMP climatology data.""" registry = dataset_registry_manager[_REGISTRY_NAME] diff --git a/packages/climate-ref-pmp/src/climate_ref_pmp/diagnostics/enso.py b/packages/climate-ref-pmp/src/climate_ref_pmp/diagnostics/enso.py index 3c2a11ca7..9980e8b80 100644 --- a/packages/climate-ref-pmp/src/climate_ref_pmp/diagnostics/enso.py +++ b/packages/climate-ref-pmp/src/climate_ref_pmp/diagnostics/enso.py @@ -95,7 +95,7 @@ def __init__(self, metrics_collection: str, experiments: Collection[str] = ("his RegistryRequest( slug=f"enso-{self.slug}-obs", registry_name="obs4ref", - source_type="obs4MIPs", + source_type="obs4REF", facets={ "source_id": self.obs_sources, "variable_id": self.model_variables, @@ -141,7 +141,7 @@ def __init__(self, metrics_collection: str, experiments: Collection[str] = ("his RegistryRequest( slug=f"enso-{self.slug}-obs-cmip7", registry_name="obs4ref", - source_type="obs4MIPs", + source_type="obs4REF", facets={ "source_id": self.obs_sources, "variable_id": self.model_variables, diff --git a/packages/climate-ref-pmp/src/climate_ref_pmp/diagnostics/variability_modes.py b/packages/climate-ref-pmp/src/climate_ref_pmp/diagnostics/variability_modes.py index 2ffdc817c..37dbb6d66 100644 --- a/packages/climate-ref-pmp/src/climate_ref_pmp/diagnostics/variability_modes.py +++ b/packages/climate-ref-pmp/src/climate_ref_pmp/diagnostics/variability_modes.py @@ -121,7 +121,7 @@ def _get_data_requirements( RegistryRequest( slug=f"mov-{self.mode_id.lower()}-obs", registry_name="obs4ref", - source_type="obs4MIPs", + source_type="obs4REF", facets={"source_id": "HadISST-1-1", "variable_id": "ts"}, ), CMIP6Request( @@ -144,7 +144,7 @@ def _get_data_requirements( RegistryRequest( slug=f"mov-{self.mode_id.lower()}-obs-cmip7", registry_name="obs4ref", - source_type="obs4MIPs", + source_type="obs4REF", facets={"source_id": "HadISST-1-1", "variable_id": "ts"}, ), CMIP7Request( diff --git a/packages/climate-ref-pmp/tests/test-data/enso_proc/cmip6/catalog.yaml b/packages/climate-ref-pmp/tests/test-data/enso_proc/cmip6/catalog.yaml index 87cca19ce..0f05a929a 100644 --- a/packages/climate-ref-pmp/tests/test-data/enso_proc/cmip6/catalog.yaml +++ b/packages/climate-ref-pmp/tests/test-data/enso_proc/cmip6/catalog.yaml @@ -3,16 +3,16 @@ _metadata: obs4mips: slug_column: instance_id selector: - activity_id: obs4MIPs + activity_id: obs4REF datasets: - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2017-07-16 12:00:00' filename: hfls_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc finalised: true frequency: mon grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.ESSO.TropFlux-1-0.mon.hfls.250km.gn.v20250415 + instance_id: obs4REF.obs4REF.ESSO.TropFlux-1-0.mon.hfls.250km.gn.v20250415 institution_id: ESSO long_name: Surface Upward Latent Heat Flux nominal_resolution: 250 km @@ -28,14 +28,14 @@ obs4mips: variant_label: PCMDI version: v20250415 vertical_levels: 1 - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2017-07-16 12:00:00' filename: hfss_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc finalised: true frequency: mon grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.ESSO.TropFlux-1-0.mon.hfss.250km.gn.v20250415 + instance_id: obs4REF.obs4REF.ESSO.TropFlux-1-0.mon.hfss.250km.gn.v20250415 institution_id: ESSO long_name: Surface Upward Sensible Heat Flux nominal_resolution: 250 km @@ -51,14 +51,14 @@ obs4mips: variant_label: PCMDI version: v20250415 vertical_levels: 1 - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2017-07-16 12:00:00' filename: tauu_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc finalised: true frequency: mon grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.ESSO.TropFlux-1-0.mon.tauu.250km.gn.v20250415 + instance_id: obs4REF.obs4REF.ESSO.TropFlux-1-0.mon.tauu.250km.gn.v20250415 institution_id: ESSO long_name: Surface Downward Eastward Wind Stress nominal_resolution: 250 km @@ -74,14 +74,14 @@ obs4mips: variant_label: PCMDI version: v20250415 vertical_levels: 1 - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2017-07-15 12:00:00' filename: ts_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc finalised: true frequency: mon grid: 1.0x1.0 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.ESSO.TropFlux-1-0.mon.ts.250km.gn.v20210727 + instance_id: obs4REF.obs4REF.ESSO.TropFlux-1-0.mon.ts.250km.gn.v20210727 institution_id: ESSO long_name: Surface Temperature nominal_resolution: 250 km @@ -97,14 +97,14 @@ obs4mips: variant_label: PCMDI version: v20210727 vertical_levels: 1 - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2025-01-16 12:00:00' filename: ts_mon_HadISST-1-1_PCMDI_gn_187001-202501.nc finalised: true frequency: mon grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 + instance_id: obs4REF.obs4REF.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 institution_id: MOHC long_name: Surface Temperature nominal_resolution: 250 km @@ -120,14 +120,14 @@ obs4mips: variant_label: PCMDI version: v20250415 vertical_levels: 1 - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2023-09-16 00:00:00' filename: rlds_mon_CERES-EBAF-4-2_RSS_gn_200003-202309.nc finalised: true frequency: mon grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NASA-LaRC.CERES-EBAF-4-2.mon.rlds.100km.gn.v20230209 + instance_id: obs4REF.obs4REF.NASA-LaRC.CERES-EBAF-4-2.mon.rlds.100km.gn.v20230209 institution_id: NASA-LaRC long_name: Surface Downwelling Longwave Radiation nominal_resolution: 100 km @@ -143,14 +143,14 @@ obs4mips: variant_label: RSS version: v20230209 vertical_levels: 1 - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2023-09-16 00:00:00' filename: rlus_mon_CERES-EBAF-4-2_RSS_gn_200003-202309.nc finalised: true frequency: mon grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NASA-LaRC.CERES-EBAF-4-2.mon.rlus.100km.gn.v20230209 + instance_id: obs4REF.obs4REF.NASA-LaRC.CERES-EBAF-4-2.mon.rlus.100km.gn.v20230209 institution_id: NASA-LaRC long_name: Surface Upwelling Longwave Radiation nominal_resolution: 100 km @@ -166,14 +166,14 @@ obs4mips: variant_label: RSS version: v20230209 vertical_levels: 1 - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2023-09-16 00:00:00' filename: rsds_mon_CERES-EBAF-4-2_RSS_gn_200003-202309.nc finalised: true frequency: mon grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NASA-LaRC.CERES-EBAF-4-2.mon.rsds.100km.gn.v20230209 + instance_id: obs4REF.obs4REF.NASA-LaRC.CERES-EBAF-4-2.mon.rsds.100km.gn.v20230209 institution_id: NASA-LaRC long_name: Surface Downwelling Shortwave Radiation nominal_resolution: 100 km @@ -189,14 +189,14 @@ obs4mips: variant_label: RSS version: v20230209 vertical_levels: 1 - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2023-09-16 00:00:00' filename: rsus_mon_CERES-EBAF-4-2_RSS_gn_200003-202309.nc finalised: true frequency: mon grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NASA-LaRC.CERES-EBAF-4-2.mon.rsus.100km.gn.v20230209 + instance_id: obs4REF.obs4REF.NASA-LaRC.CERES-EBAF-4-2.mon.rsus.100km.gn.v20230209 institution_id: NASA-LaRC long_name: Surface Upwelling Shortwave Radiation nominal_resolution: 100 km diff --git a/packages/climate-ref-pmp/tests/test-data/enso_proc/cmip7/catalog.yaml b/packages/climate-ref-pmp/tests/test-data/enso_proc/cmip7/catalog.yaml index 01122a088..77a72d169 100644 --- a/packages/climate-ref-pmp/tests/test-data/enso_proc/cmip7/catalog.yaml +++ b/packages/climate-ref-pmp/tests/test-data/enso_proc/cmip7/catalog.yaml @@ -3,16 +3,16 @@ _metadata: obs4mips: slug_column: instance_id selector: - activity_id: obs4MIPs + activity_id: obs4REF datasets: - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2017-07-16 12:00:00' filename: hfls_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc finalised: true frequency: mon grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.ESSO.TropFlux-1-0.mon.hfls.250km.gn.v20250415 + instance_id: obs4REF.obs4REF.ESSO.TropFlux-1-0.mon.hfls.250km.gn.v20250415 institution_id: ESSO long_name: Surface Upward Latent Heat Flux nominal_resolution: 250 km @@ -28,14 +28,14 @@ obs4mips: variant_label: PCMDI version: v20250415 vertical_levels: 1 - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2017-07-16 12:00:00' filename: hfss_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc finalised: true frequency: mon grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.ESSO.TropFlux-1-0.mon.hfss.250km.gn.v20250415 + instance_id: obs4REF.obs4REF.ESSO.TropFlux-1-0.mon.hfss.250km.gn.v20250415 institution_id: ESSO long_name: Surface Upward Sensible Heat Flux nominal_resolution: 250 km @@ -51,14 +51,14 @@ obs4mips: variant_label: PCMDI version: v20250415 vertical_levels: 1 - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2017-07-16 12:00:00' filename: tauu_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc finalised: true frequency: mon grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.ESSO.TropFlux-1-0.mon.tauu.250km.gn.v20250415 + instance_id: obs4REF.obs4REF.ESSO.TropFlux-1-0.mon.tauu.250km.gn.v20250415 institution_id: ESSO long_name: Surface Downward Eastward Wind Stress nominal_resolution: 250 km @@ -74,14 +74,14 @@ obs4mips: variant_label: PCMDI version: v20250415 vertical_levels: 1 - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2017-07-15 12:00:00' filename: ts_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc finalised: true frequency: mon grid: 1.0x1.0 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.ESSO.TropFlux-1-0.mon.ts.250km.gn.v20210727 + instance_id: obs4REF.obs4REF.ESSO.TropFlux-1-0.mon.ts.250km.gn.v20210727 institution_id: ESSO long_name: Surface Temperature nominal_resolution: 250 km @@ -97,14 +97,14 @@ obs4mips: variant_label: PCMDI version: v20210727 vertical_levels: 1 - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2025-01-16 12:00:00' filename: ts_mon_HadISST-1-1_PCMDI_gn_187001-202501.nc finalised: true frequency: mon grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 + instance_id: obs4REF.obs4REF.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 institution_id: MOHC long_name: Surface Temperature nominal_resolution: 250 km @@ -120,14 +120,14 @@ obs4mips: variant_label: PCMDI version: v20250415 vertical_levels: 1 - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2023-09-16 00:00:00' filename: rlds_mon_CERES-EBAF-4-2_RSS_gn_200003-202309.nc finalised: true frequency: mon grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NASA-LaRC.CERES-EBAF-4-2.mon.rlds.100km.gn.v20230209 + instance_id: obs4REF.obs4REF.NASA-LaRC.CERES-EBAF-4-2.mon.rlds.100km.gn.v20230209 institution_id: NASA-LaRC long_name: Surface Downwelling Longwave Radiation nominal_resolution: 100 km @@ -143,14 +143,14 @@ obs4mips: variant_label: RSS version: v20230209 vertical_levels: 1 - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2023-09-16 00:00:00' filename: rlus_mon_CERES-EBAF-4-2_RSS_gn_200003-202309.nc finalised: true frequency: mon grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NASA-LaRC.CERES-EBAF-4-2.mon.rlus.100km.gn.v20230209 + instance_id: obs4REF.obs4REF.NASA-LaRC.CERES-EBAF-4-2.mon.rlus.100km.gn.v20230209 institution_id: NASA-LaRC long_name: Surface Upwelling Longwave Radiation nominal_resolution: 100 km @@ -166,14 +166,14 @@ obs4mips: variant_label: RSS version: v20230209 vertical_levels: 1 - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2023-09-16 00:00:00' filename: rsds_mon_CERES-EBAF-4-2_RSS_gn_200003-202309.nc finalised: true frequency: mon grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NASA-LaRC.CERES-EBAF-4-2.mon.rsds.100km.gn.v20230209 + instance_id: obs4REF.obs4REF.NASA-LaRC.CERES-EBAF-4-2.mon.rsds.100km.gn.v20230209 institution_id: NASA-LaRC long_name: Surface Downwelling Shortwave Radiation nominal_resolution: 100 km @@ -189,14 +189,14 @@ obs4mips: variant_label: RSS version: v20230209 vertical_levels: 1 - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2023-09-16 00:00:00' filename: rsus_mon_CERES-EBAF-4-2_RSS_gn_200003-202309.nc finalised: true frequency: mon grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NASA-LaRC.CERES-EBAF-4-2.mon.rsus.100km.gn.v20230209 + instance_id: obs4REF.obs4REF.NASA-LaRC.CERES-EBAF-4-2.mon.rsus.100km.gn.v20230209 institution_id: NASA-LaRC long_name: Surface Upwelling Shortwave Radiation nominal_resolution: 100 km diff --git a/packages/climate-ref-pmp/tests/test-data/enso_tel/cmip6/catalog.yaml b/packages/climate-ref-pmp/tests/test-data/enso_tel/cmip6/catalog.yaml index 612587abc..4f885a08a 100644 --- a/packages/climate-ref-pmp/tests/test-data/enso_tel/cmip6/catalog.yaml +++ b/packages/climate-ref-pmp/tests/test-data/enso_tel/cmip6/catalog.yaml @@ -3,16 +3,16 @@ _metadata: obs4mips: slug_column: instance_id selector: - activity_id: obs4MIPs + activity_id: obs4REF datasets: - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2017-07-15 12:00:00' filename: ts_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc finalised: true frequency: mon grid: 1.0x1.0 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.ESSO.TropFlux-1-0.mon.ts.250km.gn.v20210727 + instance_id: obs4REF.obs4REF.ESSO.TropFlux-1-0.mon.ts.250km.gn.v20210727 institution_id: ESSO long_name: Surface Temperature nominal_resolution: 250 km @@ -28,14 +28,14 @@ obs4mips: variant_label: PCMDI version: v20210727 vertical_levels: 1 - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2025-01-16 12:00:00' filename: ts_mon_HadISST-1-1_PCMDI_gn_187001-202501.nc finalised: true frequency: mon grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 + instance_id: obs4REF.obs4REF.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 institution_id: MOHC long_name: Surface Temperature nominal_resolution: 250 km @@ -51,14 +51,14 @@ obs4mips: variant_label: PCMDI version: v20250415 vertical_levels: 1 - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2023-03-16 12:00:00' filename: pr_mon_GPCP-Monthly-3-2_RSS_gn_198301-202303.nc finalised: true frequency: mon grid: 0.5x0.5 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NASA-GSFC.GPCP-Monthly-3-2.mon.pr.50km.gn.v20231205 + instance_id: obs4REF.obs4REF.NASA-GSFC.GPCP-Monthly-3-2.mon.pr.50km.gn.v20231205 institution_id: NASA-GSFC long_name: Precipitation nominal_resolution: 50 km diff --git a/packages/climate-ref-pmp/tests/test-data/enso_tel/cmip7/catalog.yaml b/packages/climate-ref-pmp/tests/test-data/enso_tel/cmip7/catalog.yaml index 9c7453999..8c66352c1 100644 --- a/packages/climate-ref-pmp/tests/test-data/enso_tel/cmip7/catalog.yaml +++ b/packages/climate-ref-pmp/tests/test-data/enso_tel/cmip7/catalog.yaml @@ -3,16 +3,16 @@ _metadata: obs4mips: slug_column: instance_id selector: - activity_id: obs4MIPs + activity_id: obs4REF datasets: - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2017-07-15 12:00:00' filename: ts_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc finalised: true frequency: mon grid: 1.0x1.0 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.ESSO.TropFlux-1-0.mon.ts.250km.gn.v20210727 + instance_id: obs4REF.obs4REF.ESSO.TropFlux-1-0.mon.ts.250km.gn.v20210727 institution_id: ESSO long_name: Surface Temperature nominal_resolution: 250 km @@ -28,14 +28,14 @@ obs4mips: variant_label: PCMDI version: v20210727 vertical_levels: 1 - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2025-01-16 12:00:00' filename: ts_mon_HadISST-1-1_PCMDI_gn_187001-202501.nc finalised: true frequency: mon grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 + instance_id: obs4REF.obs4REF.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 institution_id: MOHC long_name: Surface Temperature nominal_resolution: 250 km @@ -51,14 +51,14 @@ obs4mips: variant_label: PCMDI version: v20250415 vertical_levels: 1 - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2023-03-16 12:00:00' filename: pr_mon_GPCP-Monthly-3-2_RSS_gn_198301-202303.nc finalised: true frequency: mon grid: 0.5x0.5 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NASA-GSFC.GPCP-Monthly-3-2.mon.pr.50km.gn.v20231205 + instance_id: obs4REF.obs4REF.NASA-GSFC.GPCP-Monthly-3-2.mon.pr.50km.gn.v20231205 institution_id: NASA-GSFC long_name: Precipitation nominal_resolution: 50 km diff --git a/packages/climate-ref-pmp/tests/test-data/extratropical-modes-of-variability-npgo/cmip6/catalog.yaml b/packages/climate-ref-pmp/tests/test-data/extratropical-modes-of-variability-npgo/cmip6/catalog.yaml index 59a287e01..0d2ef2e30 100644 --- a/packages/climate-ref-pmp/tests/test-data/extratropical-modes-of-variability-npgo/cmip6/catalog.yaml +++ b/packages/climate-ref-pmp/tests/test-data/extratropical-modes-of-variability-npgo/cmip6/catalog.yaml @@ -6,14 +6,14 @@ obs4mips: source_id: HadISST-1-1 variable_id: ts datasets: - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2025-01-16 12:00:00' filename: ts_mon_HadISST-1-1_PCMDI_gn_187001-202501.nc finalised: true frequency: mon grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 + instance_id: obs4REF.obs4REF.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 institution_id: MOHC long_name: Surface Temperature nominal_resolution: 250 km diff --git a/packages/climate-ref-pmp/tests/test-data/extratropical-modes-of-variability-npgo/cmip7/catalog.yaml b/packages/climate-ref-pmp/tests/test-data/extratropical-modes-of-variability-npgo/cmip7/catalog.yaml index e3daf6796..1f0d6831a 100644 --- a/packages/climate-ref-pmp/tests/test-data/extratropical-modes-of-variability-npgo/cmip7/catalog.yaml +++ b/packages/climate-ref-pmp/tests/test-data/extratropical-modes-of-variability-npgo/cmip7/catalog.yaml @@ -6,14 +6,14 @@ obs4mips: source_id: HadISST-1-1 variable_id: ts datasets: - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2025-01-16 12:00:00' filename: ts_mon_HadISST-1-1_PCMDI_gn_187001-202501.nc finalised: true frequency: mon grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 + instance_id: obs4REF.obs4REF.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 institution_id: MOHC long_name: Surface Temperature nominal_resolution: 250 km diff --git a/packages/climate-ref-pmp/tests/test-data/extratropical-modes-of-variability-pdo/cmip6/catalog.yaml b/packages/climate-ref-pmp/tests/test-data/extratropical-modes-of-variability-pdo/cmip6/catalog.yaml index 59a287e01..0d2ef2e30 100644 --- a/packages/climate-ref-pmp/tests/test-data/extratropical-modes-of-variability-pdo/cmip6/catalog.yaml +++ b/packages/climate-ref-pmp/tests/test-data/extratropical-modes-of-variability-pdo/cmip6/catalog.yaml @@ -6,14 +6,14 @@ obs4mips: source_id: HadISST-1-1 variable_id: ts datasets: - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2025-01-16 12:00:00' filename: ts_mon_HadISST-1-1_PCMDI_gn_187001-202501.nc finalised: true frequency: mon grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 + instance_id: obs4REF.obs4REF.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 institution_id: MOHC long_name: Surface Temperature nominal_resolution: 250 km diff --git a/packages/climate-ref-pmp/tests/test-data/extratropical-modes-of-variability-pdo/cmip7/catalog.yaml b/packages/climate-ref-pmp/tests/test-data/extratropical-modes-of-variability-pdo/cmip7/catalog.yaml index e3daf6796..1f0d6831a 100644 --- a/packages/climate-ref-pmp/tests/test-data/extratropical-modes-of-variability-pdo/cmip7/catalog.yaml +++ b/packages/climate-ref-pmp/tests/test-data/extratropical-modes-of-variability-pdo/cmip7/catalog.yaml @@ -6,14 +6,14 @@ obs4mips: source_id: HadISST-1-1 variable_id: ts datasets: - - activity_id: obs4MIPs + - activity_id: obs4REF end_time: '2025-01-16 12:00:00' filename: ts_mon_HadISST-1-1_PCMDI_gn_187001-202501.nc finalised: true frequency: mon grid: 1x1 degree latitude x longitude grid_label: gn - instance_id: obs4MIPs.obs4MIPs.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 + instance_id: obs4REF.obs4REF.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 institution_id: MOHC long_name: Surface Temperature nominal_resolution: 250 km diff --git a/packages/climate-ref-pmp/tests/unit/test_provider.py b/packages/climate-ref-pmp/tests/unit/test_provider.py index 2a67d4275..90e170da3 100644 --- a/packages/climate-ref-pmp/tests/unit/test_provider.py +++ b/packages/climate-ref-pmp/tests/unit/test_provider.py @@ -2,11 +2,32 @@ from pathlib import Path import pooch -from climate_ref_pmp import PMPDiagnosticProvider, __version__, provider +from climate_ref_pmp import ( + _DEFAULT_THREAD_LIMIT, + _THREAD_LIMIT_VARS, + PMPDiagnosticProvider, + __version__, + provider, +) from climate_ref_core.data import LayeredResource, PackagedResource +def configured_provider(mocker, tmp_path): + """Build a provider and run `configure` against a mock config rooted at `tmp_path`.""" + test_provider = PMPDiagnosticProvider("PMP-Test", "1.0") + mock_config = mocker.Mock() + mock_config.paths.software = tmp_path / "software" + mock_config.ignore_datasets_file = tmp_path / "ignore.yaml" + mock_config.ignore_datasets_file.touch() + mock_config.ignore_datasets_resource = LayeredResource( + packaged=PackagedResource("climate_ref", "default_ignore_datasets.yaml"), + override=mock_config.ignore_datasets_file, + ) + test_provider.configure(mock_config) + return test_provider, mock_config + + def test_provider(): assert provider.name == "PMP" assert provider.slug == "pmp" @@ -89,19 +110,11 @@ def test_validate_setup_all_valid(self, mocker): result = provider.validate_setup(mock_config) assert result is True - def test_configure_sets_env_vars(self, mocker, tmp_path): + def test_configure_sets_env_vars(self, mocker, tmp_path, monkeypatch): """Test that configure sets the required environment variables.""" - test_provider = PMPDiagnosticProvider("PMP-Test", "1.0") - mock_config = mocker.Mock() - mock_config.paths.software = tmp_path / "software" - mock_config.ignore_datasets_file = tmp_path / "ignore.yaml" - mock_config.ignore_datasets_file.touch() - mock_config.ignore_datasets_resource = LayeredResource( - packaged=PackagedResource("climate_ref", "default_ignore_datasets.yaml"), - override=mock_config.ignore_datasets_file, - ) - - test_provider.configure(mock_config) + for name in _THREAD_LIMIT_VARS: + monkeypatch.delenv(name, raising=False) + test_provider, mock_config = configured_provider(mocker, tmp_path) assert "PCMDI_CONDA_EXE" in test_provider.env_overrides # The path is recorded without installing anything, so `configure` stays offline. @@ -110,6 +123,16 @@ def test_configure_sets_env_vars(self, mocker, tmp_path): ) assert "FI_PROVIDER" in test_provider.env_overrides assert test_provider.env_overrides["FI_PROVIDER"] == "tcp" + for name in _THREAD_LIMIT_VARS: + assert test_provider.env_overrides[name] == _DEFAULT_THREAD_LIMIT + + def test_configure_keeps_user_thread_limits(self, mocker, tmp_path, monkeypatch): + """One thread limit in the environment suppresses the default for all of them.""" + monkeypatch.setenv("OMP_NUM_THREADS", "4") + test_provider, _ = configured_provider(mocker, tmp_path) + + for name in _THREAD_LIMIT_VARS: + assert name not in test_provider.env_overrides def test_ingest_data_skips_when_climate_ref_not_installed(self, mocker, caplog): """Test ingest_data gracefully skips when climate-ref package is not installed.""" diff --git a/packages/climate-ref/conftest.py b/packages/climate-ref/conftest.py index 029add526..4031c04c1 100644 --- a/packages/climate-ref/conftest.py +++ b/packages/climate-ref/conftest.py @@ -18,7 +18,7 @@ from climate_ref.datasets.cmip6_parsers import parse_cmip6_complete, parse_cmip6_drs from climate_ref.datasets.cmip7 import CMIP7DatasetAdapter from climate_ref.datasets.cmip7_parsers import parse_cmip7_complete, parse_cmip7_drs -from climate_ref.datasets.obs4mips import Obs4MIPsDatasetAdapter +from climate_ref.datasets.obs4mips import Obs4MIPsDatasetAdapter, Obs4REFDatasetAdapter from climate_ref.models.metric_value import MetricValue from climate_ref.provider_registry import _register_provider from climate_ref.solve_helpers import solve_to_results @@ -120,11 +120,12 @@ def prepare_db(cmip7_aft_cv): @pytest.fixture(scope="session") -def db_seeded_template( +def db_seeded_template( # noqa: PLR0913 tmp_path_session: Path, migrated_db_template: Path, cmip6_data_catalog, obs4mips_data_catalog, + obs4ref_data_catalog, prepare_db, ) -> Path: template_db_path = tmp_path_session / "climate_ref_template_seeded.db" @@ -140,12 +141,15 @@ def db_seeded_template( for instance_id, data_catalog_dataset in cmip6_validated.groupby(adapter.slug_column): adapter.register_dataset(database, data_catalog_dataset) - # Seed the obs4MIPs sample datasets - adapter_obs = Obs4MIPsDatasetAdapter() - obs4mips_validated = adapter_obs.validate_data_catalog(obs4mips_data_catalog) - with database.session.begin(): - for instance_id, data_catalog_dataset in obs4mips_validated.groupby(adapter_obs.slug_column): - adapter_obs.register_dataset(database, data_catalog_dataset) + # Seed the obs4MIPs and obs4REF sample datasets + for adapter_obs, catalog in ( + (Obs4MIPsDatasetAdapter(), obs4mips_data_catalog), + (Obs4REFDatasetAdapter(), obs4ref_data_catalog), + ): + validated = adapter_obs.validate_data_catalog(catalog) + with database.session.begin(): + for instance_id, data_catalog_dataset in validated.groupby(adapter_obs.slug_column): + adapter_obs.register_dataset(database, data_catalog_dataset) with database.session.begin(): _register_provider(database, example_provider) diff --git a/packages/climate-ref/pyproject.toml b/packages/climate-ref/pyproject.toml index 847fc7bde..b694ecfdf 100644 --- a/packages/climate-ref/pyproject.toml +++ b/packages/climate-ref/pyproject.toml @@ -42,6 +42,8 @@ dependencies = [ "platformdirs>=4.3.6", "tqdm>=4.67.1", "gitpython>=3.1.58", + "jinja2>=3.1", + "xarray>=2025.1", # parsl doesn't support Windows yet # We don't target Windows either, but this __might__ allow Windows users to install the package 'parsl>=2025.5.19; sys_platform != "win32"' diff --git a/packages/climate-ref/src/climate_ref/baseline_report/__init__.py b/packages/climate-ref/src/climate_ref/baseline_report/__init__.py new file mode 100644 index 000000000..8a743e7f5 --- /dev/null +++ b/packages/climate-ref/src/climate_ref/baseline_report/__init__.py @@ -0,0 +1,16 @@ +""" +Render an HTML report of the regression baselines changed on a branch. + +A mint rewrites each test case's ``manifest.json`` and uploads the curated native outputs to the +content-addressed object store. +The manifest diff therefore names every native file that changed, and both the old and the new blob +remain fetchable by digest, so the change can be reviewed without checking anything out locally. + +The pipeline runs in three stages: + +- :mod:`~climate_ref.baseline_report.collect` reads the manifests either side of the base ref. +- :mod:`~climate_ref.baseline_report.analyse` fetches text blobs and builds the diffs. +- :mod:`~climate_ref.baseline_report.render` writes the static site. + +Python decides and templates place, so no module here builds HTML. +""" diff --git a/packages/climate-ref/src/climate_ref/baseline_report/analyse.py b/packages/climate-ref/src/climate_ref/baseline_report/analyse.py new file mode 100644 index 000000000..f66ce58ac --- /dev/null +++ b/packages/climate-ref/src/climate_ref/baseline_report/analyse.py @@ -0,0 +1,973 @@ +""" +Turn a collected report into everything the templates need. + +Text blobs are fetched from the native store and diffed here. +""" + +from __future__ import annotations + +import difflib +import io +import json +from collections import Counter +from contextlib import ExitStack +from itertools import islice +from pathlib import Path, PurePosixPath +from typing import TYPE_CHECKING + +import numpy as np +import xarray as xr +from attrs import frozen + +from climate_ref.baseline_report.collect import CaseChange, FileChange, FileKind, Report + +if TYPE_CHECKING: + from climate_ref_core.regression.manifest import NativeEntry + from climate_ref_core.regression.store import NativeStore + +# A blob larger than this is summarised rather than diffed. Keeps a runaway report +# from stalling the job on the download alone. +MAX_FETCH_BYTES = 2_000_000 + +# Digest prefix shown wherever a blob is named. Long enough to identify it, short enough to read. +SHORT_DIGEST = 12 + +# A NetCDF blob larger than this is left unopened. +NETCDF_FETCH_BYTES = 100_000_000 + +# Compression means a blob under the fetch cap can still decode to far more, and each variable +# is held on both sides plus a difference. This bounds what one side may expand to. +MAX_DECODED_BYTES = 500_000_000 + +# Unified-diff lines kept per file before the rest is elided. +MAX_DIFF_LINES = 5000 + + +@frozen +class DiffLine: + """One line of a unified diff, tagged so a template can style it.""" + + kind: str + """One of ``add``, ``remove``, ``context``, ``hunk`` or ``header``.""" + + text: str + """The line itself, without a trailing newline.""" + + +@frozen +class TextDiff: + """The unified diff of one text output, or the reason there is not one.""" + + lines: tuple[DiffLine, ...] + """The diff lines, empty when :attr:`note` is set.""" + + note: str | None + """Why no diff could be produced, or ``None`` when :attr:`lines` carries one.""" + + elided: int + """Lines dropped past :data:`MAX_DIFF_LINES`.""" + + +@frozen +class Pair[T]: + """One statistic on each side of the change.""" + + old: T | None + """The value on the base ref, or ``None`` when it could not be computed.""" + + new: T | None + """The value on HEAD, or ``None`` when it could not be computed.""" + + @property + def changed(self) -> bool: + """ + Whether the two sides differ. + + Returns + ------- + : + ``True`` when the value moved, which is what emphasises it in the table. + """ + return self.old != self.new + + +@frozen +class StatRow: + """Whole-array statistics for one data variable, on each side of the change.""" + + name: str + """The variable's name.""" + + shape: Pair[str] + """Dimensions on each side, as ``180x360``, or ``scalar``.""" + + minimum: Pair[float] + """Minimum on each side, ignoring NaN.""" + + maximum: Pair[float] + """Maximum on each side, ignoring NaN.""" + + mean: Pair[float] + """Mean on each side, ignoring NaN.""" + + nan: Pair[int] + """NaN cells on each side, ``None`` when the variable is absent or not numeric.""" + + max_abs_diff: float | None + """Largest absolute change, or ``None`` when the shapes differ or a side is absent.""" + + max_rel_diff: float | None + """:attr:`max_abs_diff` over the largest magnitude on the base ref.""" + + cells_differ: int | None + """Cells that changed, counting NaN as equal to NaN.""" + + moved: bool + """Whether anything about this variable changed, which is what shades its row.""" + + @property + def differs(self) -> bool: + """ + Whether the cell by cell comparison found a change. + + Returns + ------- + : + ``True`` when at least one cell moved, which is what emphasises the diff columns. + """ + return bool(self.cells_differ) + + +@frozen +class NetcdfDiff: + """What changed inside one NetCDF file, or the reason nothing could be read.""" + + header: tuple[DiffLine, ...] + """ + The two ncdump-style headers merged into one tagged listing. + + Every line is kept rather than only the changed hunks, because the header is what tells a + reader what the file holds. + """ + + header_old: tuple[str, ...] + """The base ref's header, for reading one side on its own.""" + + header_new: tuple[str, ...] + """HEAD's header, for reading one side on its own.""" + + rows: tuple[StatRow, ...] + """One row per data variable, in name order.""" + + note: str | None + """Why the file could not be analysed, or ``None`` when it was.""" + + @property + def header_changed(self) -> bool: + """ + Whether the headers differ. + + Returns + ------- + : + ``True`` when any header line was added or removed. + """ + return any(line.kind != "context" for line in self.header) + + +@frozen +class AnalysedFile: + """One native file, with its blob URLs and whatever its kind is analysed into.""" + + change: FileChange + """The underlying change.""" + + old_url: str | None + """Store URL of the base blob, or ``None`` when the file is new.""" + + new_url: str | None + """Store URL of the head blob, or ``None`` when the file was removed.""" + + text: TextDiff | None + """The diff, set only for :attr:`~climate_ref.baseline_report.collect.FileKind.TEXT` files.""" + + netcdf: NetcdfDiff | None + """The header and stats diff, set only for + :attr:`~climate_ref.baseline_report.collect.FileKind.NETCDF` files.""" + + size_delta: int | None + """Signed byte change, or ``None`` when the file exists on only one side.""" + + +@frozen +class KindCounts: + """How many files of one kind were added, changed and removed.""" + + label: str + """The kind's name, as the report column header.""" + + added: int + """Files present only on HEAD.""" + + changed: int + """Files present on both sides with a different digest.""" + + removed: int + """Files present only on the base ref.""" + + +@frozen +class AnalysedCase: + """One test case, with its files analysed and tallied.""" + + change: CaseChange + """The underlying change.""" + + files: tuple[AnalysedFile, ...] + """Every analysed file, in the order collection produced them.""" + + counts: tuple[KindCounts, ...] + """One entry per kind, in report column order.""" + + images: tuple[AnalysedFile, ...] + """The image files, which render as a two-up comparison.""" + + texts: tuple[AnalysedFile, ...] + """The text files, which render as a diff.""" + + netcdfs: tuple[AnalysedFile, ...] + """The NetCDF files, which render as a header diff and a table of variable statistics.""" + + others: tuple[AnalysedFile, ...] + """Every remaining file, which renders as a table row.""" + + back_link: str + """Relative link from this case's page back to the index, one ``..`` per label segment.""" + + +@frozen +class AnalysedReport: + """A whole report, ready to render.""" + + report: Report + """The underlying report.""" + + store_url: str + """Base location blobs are served from, matching what :func:`blob_url` builds.""" + + cases: tuple[AnalysedCase, ...] + """The analysed cases, in the order collection produced them.""" + + kinds: tuple[str, ...] + """The count column headers, matching the order of every case's ``counts``.""" + + +def blob_url(store: NativeStore, digest: str) -> str: + """ + Build the URL a blob is served from. + + A local store fans its blobs out by the first two digest characters, so a flat URL under + its root would point at nothing. + + Parameters + ---------- + store + The store the blob lives in. + digest + The blob's sha256 hex digest. + + Returns + ------- + : + An absolute URL a browser can open. + """ + if store.root is not None: + return (store.root / digest[:2] / digest).absolute().as_uri() + return f"{store.url.rstrip('/')}/{digest}" + + +def _as_lines(path: Path | None, name: str) -> list[str]: + """ + Decode a blob into diffable lines. + + JSON is re-serialised with indentation first, because a minified bundle would otherwise + diff as a single unreadable line. + + Parameters + ---------- + path + The fetched blob, or ``None`` when the file is absent on that side. + name + The file's name, used to decide whether it is JSON. + + Returns + ------- + : + The lines to diff. + """ + if path is None: + return [] + text = path.read_bytes().decode("utf-8", errors="replace") + if Path(name).suffix.lower() == ".json": + try: + text = json.dumps(json.loads(text), indent=2, sort_keys=True) + except json.JSONDecodeError: + pass + return text.splitlines() + + +def _classify_line(line: str) -> str: + """ + Tag one unified-diff line with the CSS class a template should use. + + Parameters + ---------- + line + The raw diff line. + + Returns + ------- + : + One of ``header``, ``hunk``, ``add``, ``remove`` or ``context``. + """ + if line.startswith(("---", "+++")): + return "header" + if line.startswith("@@"): + return "hunk" + if line.startswith("+"): + return "add" + if line.startswith("-"): + return "remove" + return "context" + + +def _diff_lines( + old_lines: list[str], + new_lines: list[str], + *, + fromfile: str, + tofile: str, +) -> tuple[tuple[DiffLine, ...], int]: + """ + Build the tagged unified diff of two line lists. + + Parameters + ---------- + old_lines + The base side, empty when it is absent. + new_lines + The head side, empty when it is absent. + fromfile + Label for the base side in the diff header. + tofile + Label for the head side in the diff header. + + Returns + ------- + : + The kept lines and the number dropped past :data:`MAX_DIFF_LINES`. + """ + raw = difflib.unified_diff(old_lines, new_lines, fromfile=fromfile, tofile=tofile, lineterm="", n=3) + kept = list(islice(raw, MAX_DIFF_LINES)) + return tuple(DiffLine(kind=_classify_line(line), text=line) for line in kept), sum(1 for _ in raw) + + +def text_diff(old: Path | None, new: Path | None, name: str) -> TextDiff: + """ + Build the unified diff between two fetched blobs. + + Parameters + ---------- + old + The base blob, or ``None`` when the file is new. + new + The head blob, or ``None`` when the file was removed. + name + The file's name, used in the diff header and to detect JSON. + + Returns + ------- + : + The diff, or a note explaining why there is not one. + """ + lines, elided = _diff_lines( + _as_lines(old, name), + _as_lines(new, name), + fromfile="old" if old is not None else "(absent)", + tofile="new" if new is not None else "(absent)", + ) + if not lines: + return TextDiff(lines=(), note="identical after decoding", elided=0) + return TextDiff(lines=lines, note=None, elided=elided) + + +def _header(dataset: xr.Dataset | None) -> list[str]: + """ + Render a dataset's ncdump-style header as lines. + + Parameters + ---------- + dataset + The open dataset, or ``None`` when the file is absent on that side. + + Returns + ------- + : + The header lines, empty when there is no dataset. + """ + if dataset is None: + return [] + buf = io.StringIO() + dataset.info(buf) + return buf.getvalue().splitlines() + + +def _header_diff(old_lines: list[str], new_lines: list[str]) -> tuple[DiffLine, ...]: + """ + Merge two headers into one listing, tagging each line. + + Unlike a unified diff this keeps every line, so the listing doubles as the file's + description rather than only naming what moved. + + Parameters + ---------- + old_lines + The base side's header, empty when that side is absent. + new_lines + The head side's header, empty when that side is absent. + + Returns + ------- + : + Every line, in reading order, tagged ``context``, ``add`` or ``remove``. The two + character marker is kept on the text so the tags survive without colour. + """ + kinds = {" ": "context", "-": "remove", "+": "add"} + return tuple( + DiffLine(kind=kinds[line[0]], text=line) + for line in difflib.Differ().compare(old_lines, new_lines) + if line[0] in kinds + ) + + +def _variable(dataset: xr.Dataset | None, name: str) -> xr.DataArray | None: + """ + Look one data variable up on one side. + + Parameters + ---------- + dataset + The open dataset, or ``None`` when the file is absent on that side. + name + The variable's name. + + Returns + ------- + : + The variable, or ``None`` when this side does not carry it. + """ + if dataset is None or name not in dataset.data_vars: + return None + return dataset[name] + + +def _values(variable: xr.DataArray | None) -> np.ndarray | None: + """ + Read one variable as a float array. + + Parameters + ---------- + variable + The variable, or ``None`` when it is absent on that side. + + Returns + ------- + : + The values in their stored dtype, or ``None`` when the variable is absent or not + numeric. The dtype is kept because an ``int64`` past 2**53 does not survive a cast to + float, so two adjacent values would compare equal. + """ + if variable is None or not np.issubdtype(variable.dtype, np.number): + return None + return np.asarray(variable.values) + + +def _shape(variable: xr.DataArray | None) -> str | None: + """ + Render one variable's shape. + + Parameters + ---------- + variable + The variable, or ``None`` when it is absent on that side. + + Returns + ------- + : + For example ``180x360``, ``scalar`` for a zero-dimensional variable, or ``None`` + when the variable is absent. + """ + if variable is None: + return None + return "x".join(str(size) for size in variable.shape) if variable.shape else "scalar" + + +def _summarise(values: np.ndarray | None) -> tuple[float | None, float | None, float | None, int | None]: + """ + Reduce one side's values to min, max, mean and NaN count. + + Parameters + ---------- + values + The float array, or ``None`` when the variable is absent or not numeric. + + Returns + ------- + : + The four statistics. The first three are ``None`` for an empty or all-NaN array, + which is what numpy would otherwise report as NaN with a warning. + """ + if values is None: + return None, None, None, None + nan_count = int(np.isnan(values).sum()) + if values.size in (0, nan_count): + return None, None, None, nan_count + return ( + float(np.nanmin(values)), + float(np.nanmax(values)), + float(np.nanmean(values, dtype=float)), + nan_count, + ) + + +def _compare( + old: np.ndarray | None, new: np.ndarray | None, scale: float +) -> tuple[float | None, float | None, int | None]: + """ + Compare two sides of the same variable cell by cell. + + NaN counts as equal to NaN, because a masked cell staying masked is not a change. + + Parameters + ---------- + old + The base side, or ``None`` when absent or not numeric. + new + The head side, or ``None`` when absent or not numeric. + scale + The base side's largest magnitude, which the relative difference is measured against. + + Returns + ------- + : + The largest absolute difference, the same relative to ``scale``, and the number of + cells that differ. The two differences are ``None`` when a cell moved between NaN and + a number, because that gap has no magnitude and the finite maximum would read as zero. + All three are ``None`` when the sides cannot be compared. + """ + if old is None or new is None or old.shape != new.shape: + return None, None, None + old_nan = np.isnan(old) + new_nan = np.isnan(new) + cells_differ = int(np.sum(~((old == new) | (old_nan & new_nan)))) + if np.any(old_nan != new_nan): + return None, None, cells_differ + diff = np.abs(new.astype(float) - old.astype(float)) + max_abs = 0.0 if np.isnan(diff).all() else float(np.nanmax(diff)) + return max_abs, max_abs / max(scale, float(np.finfo(float).tiny)), cells_differ + + +def _stat_row(old: xr.Dataset | None, new: xr.Dataset | None, name: str) -> StatRow: + """ + Build one variable's row. + + Parameters + ---------- + old + The base dataset, or ``None`` when the file is absent on that side. + new + The head dataset, or ``None`` when the file is absent on that side. + name + The variable's name. + + Returns + ------- + : + The row, with ``moved`` set when the shape or any cell changed. + """ + old_variable = _variable(old, name) + new_variable = _variable(new, name) + shape_old = _shape(old_variable) + shape_new = _shape(new_variable) + old_values = _values(old_variable) + new_values = _values(new_variable) + min_old, max_old, mean_old, nan_old = _summarise(old_values) + min_new, max_new, mean_new, nan_new = _summarise(new_values) + scale = max(abs(min_old), abs(max_old)) if min_old is not None and max_old is not None else 0.0 + max_abs_diff, max_rel_diff, cells_differ = _compare(old_values, new_values, scale) + shape = Pair(old=shape_old, new=shape_new) + return StatRow( + name=name, + shape=shape, + minimum=Pair(old=min_old, new=min_new), + maximum=Pair(old=max_old, new=max_new), + mean=Pair(old=mean_old, new=mean_new), + nan=Pair(old=nan_old, new=nan_new), + max_abs_diff=max_abs_diff, + max_rel_diff=max_rel_diff, + cells_differ=cells_differ, + moved=(cells_differ or 0) > 0 or shape.changed, + ) + + +def netcdf_diff(old: Path | None, new: Path | None) -> NetcdfDiff: + """ + Diff the headers and whole-array statistics of two NetCDF blobs. + + Decoding is turned off so a non-standard calendar or unit cannot fail the report. + + Parameters + ---------- + old + The base blob, or ``None`` when the file is new. + new + The head blob, or ``None`` when the file was removed. + + Returns + ------- + : + The header diff and one row per data variable, or a note when a file could not be opened. + """ + try: + with ExitStack() as stack: + old_ds = ( + stack.enter_context(xr.open_dataset(old, decode_times=False, decode_cf=False)) + if old is not None + else None + ) + new_ds = ( + stack.enter_context(xr.open_dataset(new, decode_times=False, decode_cf=False)) + if new is not None + else None + ) + for dataset in (old_ds, new_ds): + if dataset is not None and dataset.nbytes > MAX_DECODED_BYTES: + return NetcdfDiff( + header=(), + header_old=(), + header_new=(), + rows=(), + note=f"decodes to too much to analyse ({dataset.nbytes:,} B)", + ) + header_old = _header(old_ds) + header_new = _header(new_ds) + header = _header_diff(header_old, header_new) + names = sorted( + { + str(name) + for dataset in (old_ds, new_ds) + if dataset is not None + for name in dataset.data_vars + } + ) + rows = tuple(_stat_row(old_ds, new_ds, name) for name in names) + except (OSError, ValueError, KeyError) as exc: + return NetcdfDiff(header=(), header_old=(), header_new=(), rows=(), note=f"could not open: {exc}") + return NetcdfDiff( + header=header, + header_old=tuple(header_old), + header_new=tuple(header_new), + rows=rows, + note=None, + ) + + +def _fetch_side( + store: NativeStore, + entry: NativeEntry | None, + workdir: Path, + *, + limit: int, + oversize: str, +) -> tuple[Path | None, str | None]: + """ + Fetch one side of a file. + + Parameters + ---------- + store + The store to read from. + entry + The manifest entry, or ``None`` when the file is absent on that side. + workdir + Directory the blob is written into. + limit + Largest blob worth downloading. + oversize + Note to return when the blob is past ``limit``. + + Returns + ------- + : + A ``(path, note)`` pair. ``path`` is ``None`` when the blob is absent or unfetchable, + and ``note`` describes a failure. + """ + if entry is None: + return None, None + if entry.size > limit: + return None, f"{oversize} ({entry.size:,} B)" + digest = entry.sha256 + dest = workdir / digest + if dest.exists(): + return dest, None + try: + store.fetch(digest, dest) + except (OSError, ValueError) as exc: + return None, f"could not fetch {digest[:SHORT_DIGEST]} ({exc})" + return dest, None + + +def _fetch_pair( + change: FileChange, + store: NativeStore, + workdir: Path, + *, + limit: int, + oversize: str, +) -> tuple[Path | None, Path | None, str | None]: + """ + Fetch both sides of a file. + + Parameters + ---------- + change + The file that moved. + store + The store to read blobs from. + workdir + Directory fetched blobs are written into. + limit + Largest blob worth downloading. + oversize + Note to return when a blob is past ``limit``. + + Returns + ------- + : + An ``(old, new, note)`` triple. ``note`` is the first failure of the two sides, and + the paths should be ignored once it is set. + """ + old_path, old_note = _fetch_side(store, change.old, workdir, limit=limit, oversize=oversize) + new_path, new_note = _fetch_side(store, change.new, workdir, limit=limit, oversize=oversize) + return old_path, new_path, old_note or new_note + + +def _diff_for( + change: FileChange, + store: NativeStore, + *, + fetch: bool, + workdir: Path, +) -> TextDiff | None: + """ + Build the diff for one file, or ``None`` when its kind is not diffed. + + Parameters + ---------- + change + The file that moved. + store + The store to read blobs from. + fetch + Whether blobs may be downloaded. + workdir + Directory fetched blobs are written into. + + Returns + ------- + : + The diff, a note explaining why there is not one, or ``None`` for a non-text file. + """ + if change.kind is not FileKind.TEXT: + return None + if not fetch: + return TextDiff(lines=(), note="fetching disabled", elided=0) + + old_path, new_path, note = _fetch_pair( + change, store, workdir, limit=MAX_FETCH_BYTES, oversize="too large to diff" + ) + if note is not None: + return TextDiff(lines=(), note=note, elided=0) + return text_diff(old_path, new_path, change.name) + + +def _netcdf_for( + change: FileChange, + store: NativeStore, + *, + fetch: bool, + workdir: Path, +) -> NetcdfDiff | None: + """ + Build the NetCDF analysis for one file, or ``None`` when its kind is not NetCDF. + + Parameters + ---------- + change + The file that moved. + store + The store to read blobs from. + fetch + Whether blobs may be downloaded. + workdir + Directory fetched blobs are written into. + + Returns + ------- + : + The analysis, a note explaining why there is not one, or ``None`` for another kind. + """ + if change.kind is not FileKind.NETCDF: + return None + if not fetch: + return NetcdfDiff(header=(), header_old=(), header_new=(), rows=(), note="fetching disabled") + + old_path, new_path, note = _fetch_pair( + change, store, workdir, limit=NETCDF_FETCH_BYTES, oversize="too large to analyse" + ) + if note is not None: + return NetcdfDiff(header=(), header_old=(), header_new=(), rows=(), note=note) + return netcdf_diff(old_path, new_path) + + +def _analyse_file( + change: FileChange, + store: NativeStore, + *, + fetch: bool, + workdir: Path, +) -> AnalysedFile: + """ + Build the URLs and, for text and NetCDF, the analysis of one native file. + + Parameters + ---------- + change + The file that moved. + store + The store to read blobs from. + fetch + Whether blobs may be downloaded. + workdir + Directory fetched blobs are written into. + + Returns + ------- + : + The analysed file. + """ + return AnalysedFile( + change=change, + old_url=blob_url(store, change.old.sha256) if change.old else None, + new_url=blob_url(store, change.new.sha256) if change.new else None, + text=_diff_for(change, store, fetch=fetch, workdir=workdir), + netcdf=_netcdf_for(change, store, fetch=fetch, workdir=workdir), + size_delta=change.new.size - change.old.size if change.old and change.new else None, + ) + + +def _of_kind(files: tuple[AnalysedFile, ...], kind: FileKind) -> tuple[AnalysedFile, ...]: + """ + Select the files of one kind, keeping their order. + + Parameters + ---------- + files + The analysed files. + kind + The kind to keep. + + Returns + ------- + : + The matching files. + """ + return tuple(file for file in files if file.change.kind is kind) + + +def _counts(files: tuple[AnalysedFile, ...]) -> tuple[KindCounts, ...]: + """ + Tally each file kind's added, changed and removed counts. + + Parameters + ---------- + files + The analysed files. + + Returns + ------- + : + One entry per kind, in report column order, so a template never has to test + for a missing kind or decide the column order itself. + """ + tally: dict[FileKind, Counter[str]] = {kind: Counter() for kind in FileKind} + for analysed in files: + tally[analysed.change.kind][analysed.change.status] += 1 + return tuple( + KindCounts( + label=kind.value, + added=tally[kind]["added"], + changed=tally[kind]["changed"], + removed=tally[kind]["removed"], + ) + for kind in FileKind + ) + + +def analyse(report: Report, store: NativeStore, *, fetch: bool, workdir: Path) -> AnalysedReport: + """ + Build everything the templates need from a collected report. + + A blob that cannot be fetched becomes a note on its file rather than an exception, because + one unreachable object should not cost the whole report. + + Parameters + ---------- + report + The collected report. + store + The store to read blobs from. + fetch + Whether blobs may be downloaded. With ``False`` every text file carries a note instead + of a diff and the store is never called. + workdir + Directory fetched blobs are written into. + + Returns + ------- + : + The analysed report. + """ + store_url = store.root.absolute().as_uri() if store.root is not None else store.url.rstrip("/") + cases = [] + for case in report.cases: + files = tuple(_analyse_file(change, store, fetch=fetch, workdir=workdir) for change in case.files) + depth = len(PurePosixPath(case.label).parts) + cases.append( + AnalysedCase( + change=case, + files=files, + counts=_counts(files), + images=_of_kind(files, FileKind.IMAGE), + texts=_of_kind(files, FileKind.TEXT), + netcdfs=_of_kind(files, FileKind.NETCDF), + others=_of_kind(files, FileKind.OTHER), + back_link="/".join([*[".."] * depth, "index.html"]), + ) + ) + return AnalysedReport( + report=report, + store_url=store_url, + cases=tuple(cases), + kinds=tuple(kind.value for kind in FileKind), + ) diff --git a/packages/climate-ref/src/climate_ref/baseline_report/collect.py b/packages/climate-ref/src/climate_ref/baseline_report/collect.py new file mode 100644 index 000000000..820310e2f --- /dev/null +++ b/packages/climate-ref/src/climate_ref/baseline_report/collect.py @@ -0,0 +1,361 @@ +""" +Read the manifests either side of a base ref and pair up every native file that moved. + +Collection performs no network access. Fetching blobs and building diffs is +:mod:`~climate_ref.baseline_report.analyse`'s job. +""" + +from __future__ import annotations + +import enum +from pathlib import Path +from typing import TYPE_CHECKING + +from attrs import frozen +from loguru import logger + +from climate_ref_core.regression.manifest import Manifest, NativeEntry + +if TYPE_CHECKING: + from git import Repo + +# A manifest path needs a diagnostic and test-case directory before a label can be built from it. +_MIN_LABEL_PARTS = 3 + +IMAGE_SUFFIXES = frozenset({".png", ".jpg", ".jpeg", ".gif", ".svg"}) +"""Extensions rendered as a two-up image comparison.""" + +TEXT_SUFFIXES = frozenset({".json", ".csv", ".yml", ".yaml", ".html", ".txt", ".md", ".log"}) +"""Extensions whose blobs are worth fetching and diffing line by line.""" + +NETCDF_SUFFIXES = frozenset({".nc"}) +"""Extensions reported as a size delta and a link rather than a content diff.""" + + +class FileKind(enum.Enum): + """How a native output file should be presented in the report.""" + + IMAGE = "image" + TEXT = "text" + NETCDF = "netcdf" + OTHER = "other" + + +def classify(name: str) -> FileKind: + """ + Classify a native output file by its extension. + + Parameters + ---------- + name + The file's path relative to the test case's native output directory. + + Returns + ------- + : + The kind that decides how the file is rendered. + """ + suffix = Path(name).suffix.lower() + if suffix in IMAGE_SUFFIXES: + return FileKind.IMAGE + if suffix in TEXT_SUFFIXES: + return FileKind.TEXT + if suffix in NETCDF_SUFFIXES: + return FileKind.NETCDF + return FileKind.OTHER + + +@frozen +class FileChange: + """One native output file that was added, removed, or changed by the mint.""" + + name: str + """Path of the file relative to the test case's native output directory.""" + + old: NativeEntry | None + """The manifest entry on the base ref, or ``None`` when the file is new.""" + + new: NativeEntry | None + """The manifest entry on HEAD, or ``None`` when the file was removed.""" + + kind: FileKind + """How the file should be rendered.""" + + @property + def status(self) -> str: + """``added``, ``removed`` or ``changed``.""" + if self.old is None: + return "added" + if self.new is None: + return "removed" + return "changed" + + +@frozen +class CaseChange: + """Everything that changed for a single test case.""" + + label: str + """``provider/diagnostic/test-case``.""" + + rel_path: str + """Repo-relative path of the case's ``manifest.json``.""" + + base: Manifest | None + """The manifest on the base ref, or ``None`` when the case is new.""" + + head: Manifest | None + """The manifest on HEAD, or ``None`` when the case was removed.""" + + files: tuple[FileChange, ...] + """Every native file that moved, in name order.""" + + committed: tuple[str, ...] + """Committed artefacts whose digest moved, described one per entry.""" + + metadata: tuple[str, ...] + """Scalar manifest fields that moved, described one per entry.""" + + @property + def is_new(self) -> bool: + """Whether the whole test case is new on this branch.""" + return self.base is None + + @property + def is_removed(self) -> bool: + """Whether the whole test case was deleted on this branch.""" + return self.head is None + + +@frozen +class Report: + """Every test case whose baseline moved on this branch.""" + + base_ref: str + """The git ref HEAD was compared against.""" + + head_sha: str + """The full sha of the commit that was compared.""" + + cases: tuple[CaseChange, ...] + """The changed cases, in label order.""" + + +def changed_manifests(repo: Repo, base: str) -> list[str]: + """ + Return the repo-relative paths of every test-case manifest that differs from ``base``. + + Uses the merge-base (``base...HEAD``) so commits landing on the base branch after the + feature branch forked are not misreported as baseline changes. + + Parameters + ---------- + repo + The repository to diff in. + base + The git ref to compare against. + + Returns + ------- + : + The manifest paths, sorted. + """ + from git import GitCommandError # noqa: PLC0415 + + pathspec = ":(glob)packages/**/test-data/**/manifest.json" + try: + out = repo.git.diff("--name-only", f"{base}...HEAD", "--", pathspec) + except GitCommandError: + # A shallow clone may have no merge-base with the base ref. A two-dot diff over-reports + # (it also shows base-branch commits), which is the safe direction for a report. + out = repo.git.diff("--name-only", base, "HEAD", "--", pathspec) + return sorted(line for line in out.splitlines() if line.strip()) + + +def load_at_ref(repo: Repo, ref: str, rel_path: str) -> Manifest | None: + """ + Load a manifest as it exists at ``ref``, or ``None`` when absent there. + + Parameters + ---------- + repo + The repository to read from. + ref + The git ref to read the manifest at. + rel_path + Repo-relative path of the manifest. + + Returns + ------- + : + The parsed manifest, or ``None`` when the path does not exist at ``ref``. + """ + from git import GitCommandError # noqa: PLC0415 + + try: + text = repo.git.show(f"{ref}:{rel_path}") + except GitCommandError: + return None + return Manifest.loads(text, source=f"{ref}:{rel_path}") + + +def case_label(rel_path: str) -> str: + """ + Derive a ``provider/diagnostic/test-case`` label from a manifest path. + + ``packages/climate-ref-pmp/tests/test-data/annual-cycle/cmip6-ts/manifest.json`` + becomes ``pmp/annual-cycle/cmip6-ts``. + + Parameters + ---------- + rel_path + Repo-relative path of the manifest. + + Returns + ------- + : + The label. + """ + parts = Path(rel_path).parts + provider = parts[1].removeprefix("climate-ref-") if len(parts) > 1 else "?" + tail = parts[-3:-1] if len(parts) >= _MIN_LABEL_PARTS else () + return "/".join((provider, *tail)) + + +def _metadata_changes(base: Manifest | None, head: Manifest | None) -> tuple[str, ...]: + """ + Describe the scalar manifest fields that moved. + + Parameters + ---------- + base + The manifest on the base ref, or ``None``. + head + The manifest on HEAD, or ``None``. + + Returns + ------- + : + One description per changed field. + """ + if head is None: + return ("test case removed",) + if base is None: + return (f"new test case at test_case_version {head.test_case_version}",) + changes = [] + for name in ("test_case_version", "diagnostic_version", "catalog_hash", "schema"): + old, new = getattr(base, name), getattr(head, name) + if old != new: + changes.append(f"{name}: {old} -> {new}") + return tuple(changes) + + +def _committed_changes(base: Manifest | None, head: Manifest | None) -> tuple[str, ...]: + """ + Name the committed regression artefacts whose digest moved. + + Parameters + ---------- + base + The manifest on the base ref, or ``None``. + head + The manifest on HEAD, or ``None``. + + Returns + ------- + : + One description per changed artefact, in name order. + """ + old = base.committed if base else {} + new = head.committed if head else {} + out = [] + for name in sorted(set(old) | set(new)): + if old.get(name) == new.get(name): + continue + if name not in old: + out.append(f"{name} (added)") + elif name not in new: + out.append(f"{name} (removed)") + else: + out.append(name) + return tuple(out) + + +def build_case_change(repo: Repo, base: str, rel_path: str) -> CaseChange | None: + """ + Collect every change to one test case. + + A case deleted on this branch has no head manifest. It is still reported, as a removal, + because dropping a test case is a baseline change a reviewer needs to see. + + Parameters + ---------- + repo + The repository to read from. + base + The git ref to compare against. + rel_path + Repo-relative path of the case's manifest. + + Returns + ------- + : + The case's changes, or ``None`` when the manifest is absent from both sides + or cannot be parsed, both of which leave nothing to say. + """ + head_path = Path(repo.working_tree_dir or ".") / rel_path + try: + head = Manifest.load(head_path) if head_path.exists() else None + base_manifest = load_at_ref(repo, base, rel_path) + except ValueError as exc: + logger.warning(f"Skipping {rel_path}: {exc}") + return None + if head is None and base_manifest is None: + return None + + old_native = base_manifest.native if base_manifest else {} + new_native = head.native if head else {} + files = [] + for name in sorted(set(old_native) | set(new_native)): + old, new = old_native.get(name), new_native.get(name) + if old is not None and new is not None and old.sha256 == new.sha256: + continue + files.append(FileChange(name=name, old=old, new=new, kind=classify(name))) + + return CaseChange( + label=case_label(rel_path), + rel_path=rel_path, + base=base_manifest, + head=head, + files=tuple(files), + committed=_committed_changes(base_manifest, head), + metadata=_metadata_changes(base_manifest, head), + ) + + +def collect(repo: Repo, base: str) -> Report: + """ + Collect every baseline change on this branch. + + Parameters + ---------- + repo + The repository to read from. + base + The git ref to compare against. + + Returns + ------- + : + The report, with cases in label order. + """ + cases = [ + case + for rel_path in changed_manifests(repo, base) + if (case := build_case_change(repo, base, rel_path)) is not None + ] + return Report( + base_ref=base, + head_sha=repo.head.commit.hexsha, + cases=tuple(sorted(cases, key=lambda case: case.label)), + ) diff --git a/packages/climate-ref/src/climate_ref/baseline_report/render.py b/packages/climate-ref/src/climate_ref/baseline_report/render.py new file mode 100644 index 000000000..9bad05163 --- /dev/null +++ b/packages/climate-ref/src/climate_ref/baseline_report/render.py @@ -0,0 +1,340 @@ +""" +Write the static HTML report. + +Hands frozen objects to Jinja, registers the formatting filters the templates are allowed, +and writes the pages out. +""" + +from __future__ import annotations + +from pathlib import Path +from typing import TYPE_CHECKING + +from attrs import frozen +from jinja2 import Environment, PackageLoader, select_autoescape + +from climate_ref.baseline_report.analyse import SHORT_DIGEST + +if TYPE_CHECKING: + from collections.abc import Sequence + + from climate_ref.baseline_report.analyse import AnalysedCase, AnalysedReport, KindCounts + + +def _format_bytes(size: int | None) -> str: + """ + Render a byte count with thousands separators. + + Parameters + ---------- + size + The count, or ``None`` when the file is absent on that side. + + Returns + ------- + : + For example ``101,204 B``, or ``-`` when there is no count. + """ + if size is None: + return "-" + return f"{size:,} B" + + +def _format_signed(delta: int | None) -> str: + """ + Render a signed byte change. + + Parameters + ---------- + delta + The change, or ``None`` when the file exists on only one side. + + Returns + ------- + : + For example ``+1,024``, or ``-`` when there is no change to show. + """ + if delta is None: + return "-" + return f"{delta:+,}" + + +def _format_num(value: float | int | None) -> str: + """ + Render a statistic. + + Parameters + ---------- + value + The number, or ``None`` when it could not be computed. Counts arrive as ``int`` and + measurements as ``float``, and each reads better in its own format. + + Returns + ------- + : + An integer with thousands separators, a float to six significant figures, or ``-``. + """ + if value is None: + return "-" + if isinstance(value, int): + return f"{value:,}" + return f"{value:.6g}" + + +def _format_dash(value: str | None) -> str: + """ + Render a string that may be absent. + + Parameters + ---------- + value + The string, or ``None``. + + Returns + ------- + : + The string, or ``-`` when there is not one. + """ + return "-" if value is None else value + + +def _format_short(digest: str | None) -> str: + """ + Render the readable prefix of a digest. + + Parameters + ---------- + digest + The digest, or ``None``. + + Returns + ------- + : + The first twelve hex characters, or ``-`` when there is no digest. + """ + if digest is None: + return "-" + return digest[:SHORT_DIGEST] + + +def _build_env() -> Environment: + """ + Build the Jinja environment the templates in this package are rendered with. + + Escaping keys off the template name, so ``comment.md.j2`` renders unescaped. + It is markdown, where an escaped case label would show as HTML entities on GitHub. + + Returns + ------- + : + The environment, with the formatting filters the templates use. + """ + env = Environment( + loader=PackageLoader("climate_ref.baseline_report", "templates"), + autoescape=select_autoescape(enabled_extensions=("html.j2", "html")), + trim_blocks=True, + lstrip_blocks=True, + ) + env.filters["bytes"] = _format_bytes + env.filters["signed"] = _format_signed + env.filters["num"] = _format_num + env.filters["dash"] = _format_dash + env.filters["short"] = _format_short + return env + + +_env = _build_env() + + +@frozen +class CommentLink: + """One earlier report for the same pull request.""" + + label: str + """Short name for the report, typically the head sha it was built from.""" + + url: str + """Where that report is hosted.""" + + +@frozen +class CommentRow: + """One test case's row in the pull request comment table.""" + + label: str + """The test case's label, for example ``example/diag/case``.""" + + versions: str + """``v3 -> v4``, or ``new`` / ``removed`` when the case only exists on one side.""" + + counts: tuple[str, ...] + """The ``+a ~c -r`` shorthand per file kind, in the report's column order.""" + + url: str + """Link to the case's page in the hosted report.""" + + +def _shorthand(counts: KindCounts) -> str: + """ + Summarise one kind's changes as a short ``+a ~c -r`` string. + + Parameters + ---------- + counts + The tallied counts for one file kind. + + Returns + ------- + : + For example ``+1 ~2``, or ``none`` when nothing of that kind changed. + """ + parts = [ + f"+{counts.added}" if counts.added else "", + f"~{counts.changed}" if counts.changed else "", + f"-{counts.removed}" if counts.removed else "", + ] + return " ".join(p for p in parts if p) or "none" + + +def _versions(case: AnalysedCase) -> str: + """ + Describe how a case's version moved. + + Parameters + ---------- + case + The analysed case. + + Returns + ------- + : + ``v3 -> v4``, or ``new`` / ``removed`` when the case only exists on one side. + """ + if case.change.is_removed: + return "removed" + if case.change.is_new: + return "new" + base, head = case.change.base, case.change.head + assert base is not None and head is not None + return f"v{base.test_case_version} -> v{head.test_case_version}" + + +def _comment_row(case: AnalysedCase, base_url: str) -> CommentRow: + """ + Build one table row from an analysed case. + + Parameters + ---------- + case + The analysed case. + base_url + Where the report is hosted, without a trailing slash. + + Returns + ------- + : + The row. + """ + return CommentRow( + label=case.change.label, + versions=_versions(case), + counts=tuple(_shorthand(count) for count in case.counts), + url=f"{base_url}/{case.change.label}/index.html", + ) + + +def render_comment( + report: AnalysedReport, + base_url: str, + previous: Sequence[tuple[str, str]] = (), +) -> str: + """ + Render the pull request comment as markdown. + + The comment is one row per changed case and a link into the hosted report, + so it stays well inside GitHub's comment size limit however many files moved. + + Parameters + ---------- + report + The analysed report. + base_url + Where the report is hosted, for example ``https://reports.example/912/0c7e1d4abc12``. + A trailing slash is ignored. + previous + ``(label, url)`` pairs for earlier reports on the same pull request. + + Returns + ------- + : + The comment's markdown, ending in the marker the CI job finds it by. + """ + root = base_url.rstrip("/") + return _env.get_template("comment.md.j2").render( + report=report, + cases=[_comment_row(case, root) for case in report.cases], + index_url=f"{root}/index.html", + previous=[CommentLink(label=label, url=url) for label, url in previous], + ) + + +def render_index(report: AnalysedReport) -> str: + """ + Render the overview page. + + Parameters + ---------- + report + The analysed report. + + Returns + ------- + : + The page's HTML. + """ + return _env.get_template("index.html.j2").render(report=report) + + +def render_case(report: AnalysedReport, case: AnalysedCase) -> str: + """ + Render one test case's page. + + Parameters + ---------- + report + The analysed report, which carries the header details. + case + The case to render. + + Returns + ------- + : + The page's HTML. + """ + return _env.get_template("case.html.j2").render(report=report, case=case) + + +def write_site(report: AnalysedReport, out_dir: Path) -> Path: + """ + Write the overview ``index.html`` plus one ``index.html`` per case, under the case label. + + Parameters + ---------- + report + The analysed report. + out_dir + Directory to write the site into. Created if it does not exist. + + Returns + ------- + : + Path of the index page. + """ + out_dir.mkdir(parents=True, exist_ok=True) + index = out_dir / "index.html" + index.write_text(render_index(report), encoding="utf-8") + for case in report.cases: + page = out_dir / case.change.label / "index.html" + page.parent.mkdir(parents=True, exist_ok=True) + page.write_text(render_case(report, case), encoding="utf-8") + return index diff --git a/packages/climate-ref/src/climate_ref/baseline_report/templates/base.html.j2 b/packages/climate-ref/src/climate_ref/baseline_report/templates/base.html.j2 new file mode 100644 index 000000000..541f7a45b --- /dev/null +++ b/packages/climate-ref/src/climate_ref/baseline_report/templates/base.html.j2 @@ -0,0 +1,23 @@ + + + + + +{% block title %}Regression baseline diff{% endblock %} + + + +
+

Regression baseline diff

+

+Base {{ report.report.base_ref }} +against {{ report.report.head_sha | short }}. +Blobs are served from {{ report.store_url }}. +

+
+
+{% block content %}{% endblock %} +
+ + + diff --git a/packages/climate-ref/src/climate_ref/baseline_report/templates/case.html.j2 b/packages/climate-ref/src/climate_ref/baseline_report/templates/case.html.j2 new file mode 100644 index 000000000..fbebdc176 --- /dev/null +++ b/packages/climate-ref/src/climate_ref/baseline_report/templates/case.html.j2 @@ -0,0 +1,67 @@ +{% extends "base.html.j2" %} +{% import "macros.html.j2" as m %} +{% block title %}{{ case.change.label }}{% endblock %} +{% block content %} +

Back to all cases

+

{{ case.change.label }}

+{% if case.change.metadata %} + +{% endif %} +{% if case.change.committed %} +

Committed artefacts changed

+
    +{% for name in case.change.committed %} +
  • {{ name }}
  • +{% endfor %} +
+{% endif %} + +{% if case.images %} +
+Images +{% for file in case.images %} +{{ m.image_pair(file) }} +{% endfor %} +
+{% endif %} + +{% if case.texts %} +
+Text +{% for file in case.texts %} +{{ m.text_block(file) }} +{% endfor %} +
+{% endif %} + +{% if case.netcdfs %} +
+NetCDF +{% for file in case.netcdfs %} +{{ m.netcdf_block(file) }} +{% endfor %} +
+{% endif %} + +{% if case.others %} +
+Other files +
+ + + + + +{% for file in case.others %} +{{ m.binary_row(file) }} +{% endfor %} + +
filestatussizeblobs
+
+
+{% endif %} +{% endblock %} diff --git a/packages/climate-ref/src/climate_ref/baseline_report/templates/comment.md.j2 b/packages/climate-ref/src/climate_ref/baseline_report/templates/comment.md.j2 new file mode 100644 index 000000000..0c0749ddc --- /dev/null +++ b/packages/climate-ref/src/climate_ref/baseline_report/templates/comment.md.j2 @@ -0,0 +1,19 @@ +### Regression baseline diff + +{% if cases %} +{{ cases | length }} test case(s) changed against `{{ report.report.base_ref }}`. [Full report]({{ index_url }}) + +| case | versions |{% for kind in report.kinds %} {{ kind }} |{% endfor %} | +| --- | --- |{% for kind in report.kinds %} --- |{% endfor %} --- | +{% for case in cases %} +| `{{ case.label }}` | {{ case.versions }} |{% for count in case.counts %} {{ count }} |{% endfor %} [view]({{ case.url }}) | +{% endfor %} +{% else %} +No baseline manifests changed against `{{ report.report.base_ref }}`. +{% endif %} +{% if previous %} + +_Previous reports for this pull request: {% for p in previous %}[{{ p.label }}]({{ p.url }}){{ ", " if not loop.last }}{% endfor %}_ +{% endif %} + + diff --git a/packages/climate-ref/src/climate_ref/baseline_report/templates/index.html.j2 b/packages/climate-ref/src/climate_ref/baseline_report/templates/index.html.j2 new file mode 100644 index 000000000..167311d76 --- /dev/null +++ b/packages/climate-ref/src/climate_ref/baseline_report/templates/index.html.j2 @@ -0,0 +1,41 @@ +{% extends "base.html.j2" %} +{% block content %} +{% if report.cases %} + + + + + +{% for kind in report.kinds %} + +{% endfor %} + + + +{% for case in report.cases %} + + + +{% for count in case.counts %} + +{% endfor %} + +{% endfor %} + +
caseversions{{ kind }}
{{ case.change.label }} +{% if case.change.is_removed %} +removed +{% elif case.change.is_new %} +new +{% else %} +v{{ case.change.base.test_case_version }} -> v{{ case.change.head.test_case_version }} +{% endif %} + +{% if count.added %}+{{ count.added }}{% endif %} +{% if count.changed %}~{{ count.changed }}{% endif %} +{% if count.removed %}-{{ count.removed }}{% endif %} +
+{% else %} +

No baseline manifests changed against {{ report.report.base_ref }}.

+{% endif %} +{% endblock %} diff --git a/packages/climate-ref/src/climate_ref/baseline_report/templates/macros.html.j2 b/packages/climate-ref/src/climate_ref/baseline_report/templates/macros.html.j2 new file mode 100644 index 000000000..a962df093 --- /dev/null +++ b/packages/climate-ref/src/climate_ref/baseline_report/templates/macros.html.j2 @@ -0,0 +1,166 @@ +{% macro size_delta(file) -%} +{% if file.change.old is none %} +{{- file.change.new.size | bytes -}} +{% elif file.change.new is none %} +was {{ file.change.old.size | bytes -}} +{% else %} +{{- file.change.old.size | bytes }} -> {{ file.change.new.size | bytes }} ({{ file.size_delta | signed }}) +{% endif %} +{%- endmacro %} + +{% macro blob_links(file) -%} +{% if file.old_url %}old {% endif %} +{%- if file.new_url %}new{% endif %} +{%- endmacro %} + +{% macro image_pair(file) %} +
+
+{{ file.change.name }} +{{ file.change.status }} +{{ size_delta(file) }} +
+
+
+old +{% if file.old_url %} +old {{ file.change.name }} +{% else %} +
absent
+{% endif %} +
+
+new +{% if file.new_url %} +new {{ file.change.name }} +{% else %} +
absent
+{% endif %} +
+
+ +
+{% endmacro %} + +{% macro diff_lines(lines) -%} +
+{%- for line in lines %}
+{{ line.text }}
+{%- endfor %}
+
+{%- endmacro %} + +{% macro text_block(file) %} +
+

+{{ file.change.name }} +{{ file.change.status }} +{{ size_delta(file) }} + +{% if file.change.old %}{{ file.change.old.sha256 | short }}{% endif %} +{%- if file.change.new %} -> {{ file.change.new.sha256 | short }}{% endif %} + +{{ blob_links(file) }} +

+{% if file.text.note %} +

{{ file.text.note }}

+{% else %} +{{ diff_lines(file.text.lines) }} +{% if file.text.elided %} +

{{ file.text.elided }} further diff line(s) elided.

+{% endif %} +{% endif %} +
+{% endmacro %} + +{% macro binary_row(file) %} + +{{ file.change.name }} +{{ file.change.status }} +{{ size_delta(file) }} +{{ blob_links(file) }} + +{% endmacro %} + +{% macro header_side(label, lines) %} +
+{{ label }} +{% if lines %} +
+{%- for line in lines %}
+{{ line }}
+{%- endfor %}
+
+{% else %} +
absent
+{% endif %} +
+{% endmacro %} + +{% macro emphasise(value, changed) -%} +{% if changed %}{{ value }}{% else %}{{ value }}{% endif %} +{%- endmacro %} + +{% macro pair_cell(old, new, changed) -%} +{{ old }} -> {{ emphasise(new, changed) }} +{%- endmacro %} + +{% macro netcdf_block(file) %} +
+

+{{ file.change.name }} +{{ file.change.status }} +{{ size_delta(file) }} +{{ blob_links(file) }} +

+{% if file.netcdf.note %} +

{{ file.netcdf.note }}

+{% else %} +
+Header{% if not file.netcdf.header_changed %} (unchanged){% endif %} +
+
+ + +
+
+{{ diff_lines(file.netcdf.header) }} +
+ +
+
+{% if file.netcdf.rows %} +
+ + + + + + + + +{% for row in file.netcdf.rows %} + + + + + + + + + + + +{% endfor %} + +
variableshapeminmaxmeannanmax abs diffmax rel diffcells differ
{{ row.name }}{{ pair_cell(row.shape.old | dash, row.shape.new | dash, row.shape.changed) }}{{ pair_cell(row.minimum.old | num, row.minimum.new | num, row.minimum.changed) }}{{ pair_cell(row.maximum.old | num, row.maximum.new | num, row.maximum.changed) }}{{ pair_cell(row.mean.old | num, row.mean.new | num, row.mean.changed) }}{{ pair_cell(row.nan.old | num, row.nan.new | num, row.nan.changed) }}{{ emphasise(row.max_abs_diff | num, row.differs) }}{{ emphasise(row.max_rel_diff | num, row.differs) }}{{ emphasise(row.cells_differ | num, row.differs) }}
+
+{% else %} +

No data variables.

+{% endif %} +{% endif %} +
+{% endmacro %} diff --git a/packages/climate-ref/src/climate_ref/baseline_report/templates/report.css b/packages/climate-ref/src/climate_ref/baseline_report/templates/report.css new file mode 100644 index 000000000..929d37658 --- /dev/null +++ b/packages/climate-ref/src/climate_ref/baseline_report/templates/report.css @@ -0,0 +1,236 @@ +:root { + color-scheme: light dark; + --bg: #ffffff; + --fg: #1b1b1b; + --muted: #666666; + --rule: #d8d8d8; + --panel: #f6f6f6; + --add-bg: #e2f5e6; + --add-fg: #14532d; + --remove-bg: #fbe4e4; + --remove-fg: #7f1d1d; + --moved-bg: #fdeeee; +} + +@media (prefers-color-scheme: dark) { + :root { + --bg: #16181c; + --fg: #e6e6e6; + --muted: #9aa0a6; + --rule: #33363c; + --panel: #1e2126; + --add-bg: #16321f; + --add-fg: #86e29b; + --remove-bg: #3a1c1c; + --remove-fg: #f2a1a1; + --moved-bg: #2c1717; + } +} + +body { + margin: 0 auto; + padding: 1.5rem; + max-width: 72rem; + background: var(--bg); + color: var(--fg); + font-family: system-ui, -apple-system, "Segoe UI", sans-serif; + line-height: 1.45; +} + +code, pre { + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; +} + +.report-header { + border-bottom: 1px solid var(--rule); + margin-bottom: 1.5rem; +} + +.meta { + color: var(--muted); +} + +table { + border-collapse: collapse; + width: 100%; +} + +th, td { + border-bottom: 1px solid var(--rule); + padding: 0.35rem 0.5rem; + text-align: left; + vertical-align: top; +} + +.counts .added, .status.added { color: var(--add-fg); } +.counts .removed, .status.removed { color: var(--remove-fg); } +.counts .changed, .status.changed { color: var(--muted); } + +.status { + font-size: 0.85em; + text-transform: uppercase; + letter-spacing: 0.04em; +} + +.size { + color: var(--muted); + font-size: 0.9em; +} + +details { + border: 1px solid var(--rule); + border-radius: 4px; + margin: 1rem 0; + padding: 0.5rem 1rem; +} + +summary { + cursor: pointer; + font-weight: 600; +} + +.file { + border-top: 1px solid var(--rule); + margin: 1rem 0 0; + padding-top: 1rem; +} + +.pair { + display: grid; + gap: 1rem; + grid-template-columns: 1fr 1fr; + position: relative; +} + +.pair .side-label { + color: var(--muted); + display: block; + font-size: 0.85em; +} + +.pair img { + background: var(--panel); + display: block; + max-width: 100%; +} + +.pair.flipped { + grid-template-columns: 1fr; +} + +.pair.flipped .side { + grid-column: 1; + grid-row: 1; +} + +.pair.flipped .side:last-child img { + opacity: 0.5; +} + +.absent { + border: 1px dashed var(--rule); + color: var(--muted); + padding: 2rem; + text-align: center; +} + +.diff { + background: var(--panel); + border: 1px solid var(--rule); + border-radius: 4px; + max-height: 40rem; + overflow: auto; + padding: 0.5rem; +} + +.diff span { + display: block; + white-space: pre-wrap; +} + +/* A blank header line has nothing to give the block height, so keep the gap. */ +.diff span:empty::after { + content: "\00a0"; +} + +.diff .add { background: var(--add-bg); color: var(--add-fg); } +.diff .remove { background: var(--remove-bg); color: var(--remove-fg); } +.diff .hunk, .diff .header { color: var(--muted); } + +.note { + color: var(--muted); + font-style: italic; +} + +/* Table wrapper. A wide stats table scrolls inside its card rather than pushing the card wider. */ +.scroll-x { + max-width: 100%; + overflow-x: auto; +} + +.stats { + font-variant-numeric: tabular-nums; + min-width: 100%; + white-space: nowrap; + width: auto; +} + +.stats th, .stats td { + font-size: 0.9em; +} + +tr.moved { + background: var(--moved-bg); +} + +/* A baseline file name can be long and has no spaces to break on. */ +.file h3 code, .binaries code { + overflow-wrap: anywhere; +} + +.binaries td:first-child { + max-width: 40rem; +} + +.header .views { + display: flex; + gap: 0.25rem; + margin-bottom: 0.5rem; +} + +.header .views button { + background: var(--bg); + border: 1px solid var(--rule); + border-radius: 4px; + color: var(--muted); + cursor: pointer; + font-size: 0.85em; + padding: 0.15rem 0.6rem; +} + +.header .views button[aria-pressed="true"] { + background: var(--panel); + color: var(--fg); + font-weight: 600; +} + +.header .split:not([hidden]) { + display: grid; + gap: 0.75rem; + grid-template-columns: 1fr 1fr; +} + +/* Each side scrolls on its own so a long line cannot widen the other column. */ +.header .split .diff { + max-height: 30rem; + overflow: auto; +} + +.header .split .diff span { + white-space: pre; +} + +/* The moved half of a pair, so a column can be scanned for what actually shifted. */ +.stats strong { + font-weight: 600; +} diff --git a/packages/climate-ref/src/climate_ref/baseline_report/templates/report.js b/packages/climate-ref/src/climate_ref/baseline_report/templates/report.js new file mode 100644 index 000000000..864d78bed --- /dev/null +++ b/packages/climate-ref/src/climate_ref/baseline_report/templates/report.js @@ -0,0 +1,37 @@ +document.addEventListener("click", function (event) { + var target = event.target; + if (!(target instanceof Element)) { + return; + } + var button = target.closest("[data-flip]"); + if (button === null) { + return; + } + var figure = button.closest("figure"); + var pair = figure === null ? null : figure.querySelector(".pair"); + if (pair !== null) { + pair.classList.toggle("flipped"); + } +}); + +document.addEventListener("click", function (event) { + var target = event.target; + if (!(target instanceof Element)) { + return; + } + var button = target.closest("[data-header-view]"); + if (button === null) { + return; + } + var wanted = button.getAttribute("data-header-view"); + var header = button.closest("[data-header]"); + if (header === null) { + return; + } + header.querySelectorAll("[data-view]").forEach(function (view) { + view.hidden = view.getAttribute("data-view") !== wanted; + }); + header.querySelectorAll("[data-header-view]").forEach(function (other) { + other.setAttribute("aria-pressed", String(other.getAttribute("data-header-view") === wanted)); + }); +}); diff --git a/packages/climate-ref/src/climate_ref/baseline_report/upload.py b/packages/climate-ref/src/climate_ref/baseline_report/upload.py new file mode 100644 index 000000000..d14e8dd34 --- /dev/null +++ b/packages/climate-ref/src/climate_ref/baseline_report/upload.py @@ -0,0 +1,81 @@ +""" +Push a rendered report into the report store. + +The store is a plain object store with no directory semantics, +so every file is uploaded under an explicit key. +The content type has to be set per object, or a browser will download the page instead of rendering it. +""" + +from __future__ import annotations + +from pathlib import Path, PurePosixPath +from typing import TYPE_CHECKING + +from loguru import logger + +if TYPE_CHECKING: + from climate_ref_core.regression.report_store import ReportStore + +CONTENT_TYPES = { + ".html": "text/html; charset=utf-8", + ".css": "text/css; charset=utf-8", + ".js": "text/javascript; charset=utf-8", + ".png": "image/png", + ".svg": "image/svg+xml", +} +""" +Content types for the file kinds a report is made of. + +A deliberate allowlist rather than :mod:`mimetypes`, whose answers vary with the host's registry, +and which would not add the charset a browser needs on the text types. +""" + +DEFAULT_CONTENT_TYPE = "application/octet-stream" +"""Served for anything else, which a browser will offer as a download.""" + + +def content_type_for(path: Path) -> str: + """ + Return the content type a report file should be served with. + + Parameters + ---------- + path + The file, which is classified by its extension. + + Returns + ------- + : + The MIME type, or :data:`DEFAULT_CONTENT_TYPE` for an unrecognised extension. + """ + return CONTENT_TYPES.get(path.suffix.lower(), DEFAULT_CONTENT_TYPE) + + +def upload_site(out_dir: Path, store: ReportStore, prefix: str) -> str: + """ + Upload every file under ``out_dir`` as ``prefix/``. + + Parameters + ---------- + out_dir + The rendered site. + store + The store to upload into. + prefix + The key prefix the report is published under, for example ``912/0c7e1d4abc12``. + Validated by :meth:`~climate_ref_core.regression.report_store.ReportStore.put`. + + Returns + ------- + : + The URL of the report's index page, whether or not that page exists. + """ + count = 0 + for path in sorted(out_dir.rglob("*")): + if not path.is_file(): + continue + key = str(PurePosixPath(prefix, *path.relative_to(out_dir).parts)) + store.put(key, path, content_type_for(path)) + count += 1 + logger.info(f"Uploaded {count} report file(s) under {prefix}") + return store.url_for(f"{prefix}/index.html") diff --git a/packages/climate-ref/src/climate_ref/cli/test_cases/__init__.py b/packages/climate-ref/src/climate_ref/cli/test_cases/__init__.py index 03d8ff92a..fd1ce9250 100644 --- a/packages/climate-ref/src/climate_ref/cli/test_cases/__init__.py +++ b/packages/climate-ref/src/climate_ref/cli/test_cases/__init__.py @@ -10,6 +10,7 @@ - :mod:`~climate_ref.cli.test_cases.run` -- ``run`` - :mod:`~climate_ref.cli.test_cases.baselines` -- ``replay`` / ``mint`` - :mod:`~climate_ref.cli.test_cases.ci_gate` -- ``ci-gate`` +- :mod:`~climate_ref.cli.test_cases.diff` -- ``diff`` """ from importlib import import_module @@ -25,7 +26,7 @@ # Import each command module for its registration side effect on ``app``. # The sequence below is the order the verbs appear in ``ref test-cases --help`` # a dynamic import keeps it explicit, where a plain ``import`` block would be alphabetised by ruff. -for _command_module in ("discovery", "run", "baselines", "ci_gate"): +for _command_module in ("discovery", "run", "baselines", "ci_gate", "diff"): import_module(f"{__name__}.{_command_module}") __all__ = [ diff --git a/packages/climate-ref/src/climate_ref/cli/test_cases/diff.py b/packages/climate-ref/src/climate_ref/cli/test_cases/diff.py new file mode 100644 index 000000000..da7f3cf7b --- /dev/null +++ b/packages/climate-ref/src/climate_ref/cli/test_cases/diff.py @@ -0,0 +1,110 @@ +""" +``ref test-cases diff``. + +Renders an HTML report of every regression baseline that moved on this branch. +Images are shown old and new side by side and text outputs diffed inline. +""" + +from __future__ import annotations + +import tempfile +from pathlib import Path +from typing import TYPE_CHECKING, Annotated + +import typer +from loguru import logger + +from climate_ref.cli._git_utils import get_repo_for_path +from climate_ref.cli.test_cases._app import app + +if TYPE_CHECKING: + from rich.console import Console + + from climate_ref.config import Config + + +@app.command(name="diff") +def diff_baselines( # noqa: PLR0913 + ctx: typer.Context, + html_dir: Annotated[Path, typer.Option(help="Directory to write the HTML report into")], + base: Annotated[ + str, + typer.Option(help="Git ref to compare against (the PR base branch)"), + ] = "origin/main", + no_fetch: Annotated[ + bool, + typer.Option("--no-fetch", help="Skip blob downloads and report sizes only"), + ] = False, + upload: Annotated[ + str | None, + typer.Option(help="Upload the report under this key prefix, e.g. 912/0c7e1d4abc12"), + ] = None, + comment_output: Annotated[ + Path | None, + typer.Option(help="Write the pull request comment markdown here"), + ] = None, +) -> None: + """ + Render an HTML report of the regression baselines changed on this branch. + + Compares every committed ``manifest.json`` to its counterpart on ``--base`` + and writes one page per changed test case. + + Exits 0 whether or not anything changed. + + Examples + -------- + ref test-cases diff --html-dir build/baseline-diff + ref test-cases diff --base origin/develop --html-dir build/baseline-diff + ref test-cases diff --html-dir build/baseline-diff --no-fetch + ref test-cases diff --html-dir build/baseline-diff --upload 912/0c7e1d4abc12 + """ + from climate_ref.baseline_report.analyse import analyse + from climate_ref.baseline_report.collect import collect + from climate_ref.baseline_report.render import render_comment, write_site + from climate_ref.baseline_report.upload import upload_site + from climate_ref_core.regression.report_store import build_report_store + from climate_ref_core.regression.store import NativeStoreUnavailableError, build_native_store + + config: Config = ctx.obj.config + console: Console = ctx.obj.console + + repo = get_repo_for_path(Path.cwd()) + if repo is None: + logger.error("test-cases diff must be run inside a git repository") + raise typer.Exit(code=1) + + report = collect(repo, base) + store = build_native_store(config.native_store, writable=False) + with tempfile.TemporaryDirectory() as workdir: + analysed = analyse(report, store, fetch=not no_fetch, workdir=Path(workdir)) + index = write_site(analysed, html_dir) + + console.print(f"Wrote {len(analysed.cases)} case page(s) to {index}") + + base_url = None + if upload is not None: + try: + report_store = build_report_store(config.report_store, writable=True) + base_url = report_store.url_for(upload) + except ValueError as exc: + logger.error( + f"{exc} Set --upload to a relative key prefix such as 912/0c7e1d4abc12, and check " + "REF_REPORT_STORE_URL, REF_REPORT_STORE_S3_ENDPOINT_URL and REF_REPORT_STORE_BUCKET." + ) + raise typer.Exit(code=1) from exc + try: + report_store.preflight() + console.print(f"Uploaded the report to {upload_site(html_dir, report_store, upload)}") + except (ImportError, ValueError, NativeStoreUnavailableError) as exc: + logger.error( + f"Could not upload the report: {exc} Check REF_REPORT_STORE_ACCESS_KEY_ID / " + "REF_REPORT_STORE_SECRET_ACCESS_KEY and the 'climate-ref-core[aws]' extra." + ) + raise typer.Exit(code=1) from exc + + if comment_output is not None: + comment_output.parent.mkdir(parents=True, exist_ok=True) + markdown = render_comment(analysed, base_url or index.parent.resolve().as_uri()) + comment_output.write_text(markdown, encoding="utf-8") + console.print(f"Wrote the pull request comment to {comment_output}") diff --git a/packages/climate-ref/src/climate_ref/config.py b/packages/climate-ref/src/climate_ref/config.py index 00cb95a75..27ac9bc4e 100644 --- a/packages/climate-ref/src/climate_ref/config.py +++ b/packages/climate-ref/src/climate_ref/config.py @@ -289,6 +289,54 @@ def _cache_dir_factory(self) -> Path: return resolve_cache_dir("native-baselines") +@config(prefix=env_prefix) +class ReportStoreConfig: + """ + Configuration for the public store that hosts baseline diff reports. + + A diff report is a small static site keyed by pull request and head sha, + so this store is addressed by path rather than by digest. + It is a different bucket to the native store because an R2 token cannot be scoped to a prefix, + so a token that can write reports must not also be able to overwrite baseline blobs. + + Write credentials are **not** stored here: the access-key id and secret-access-key are read from + ``REF_REPORT_STORE_ACCESS_KEY_ID`` / ``REF_REPORT_STORE_SECRET_ACCESS_KEY`` + (falling back to boto3's default credential chain) at upload time only, + so secrets never land in a serialised config. + """ + + url: str = env_field(name="REPORT_STORE_URL", default="https://reports.baselines.climate-ref.org") + """ + Base URL the reports are served from. + + Reports are served at ``{url}/{key}``. + Defaults to the production Climate-REF reports endpoint. + + Set ``REF_REPORT_STORE_URL`` to a local ``file:///path/to/dir`` (or a plain filesystem path) + to render and inspect an upload offline. + """ + + s3_endpoint_url: str = env_field( + name="REPORT_STORE_S3_ENDPOINT_URL", + default="https://2aa5172b2bba093c516027d6fa13cdc8.r2.cloudflarestorage.com", + ) + """ + S3 API endpoint for the writable (Cloudflare R2) backend, without the bucket. + + Non-secret routing config, consumed only when uploading a report. + Defaults to the production Climate-REF R2 account endpoint. + Set ``REF_REPORT_STORE_S3_ENDPOINT_URL`` to override (e.g. a staging account). + """ + + bucket: str = env_field(name="REPORT_STORE_BUCKET", default="ref-baselines-reports") + """ + Name of the writable (Cloudflare R2) reports bucket. + + Non-secret routing config, consumed only when uploading a report. + Set ``REF_REPORT_STORE_BUCKET`` to override. + """ + + @config(prefix=env_prefix) class ExecutorConfig: """ @@ -752,6 +800,7 @@ class Config: paths: PathConfig = Factory(PathConfig) native_store: NativeStoreConfig = Factory(NativeStoreConfig) + report_store: ReportStoreConfig = Factory(ReportStoreConfig) db: DbConfig = Factory(DbConfig) executor: ExecutorConfig = Factory(ExecutorConfig) diagnostic_providers: list[DiagnosticProviderConfig] = Factory(default_providers) # noqa: RUF009, RUF100 diff --git a/packages/climate-ref/src/climate_ref/conftest_plugin.py b/packages/climate-ref/src/climate_ref/conftest_plugin.py index 186e95181..d1bde52e2 100644 --- a/packages/climate-ref/src/climate_ref/conftest_plugin.py +++ b/packages/climate-ref/src/climate_ref/conftest_plugin.py @@ -49,7 +49,7 @@ DiagnosticProviderConfig, ) from climate_ref.datasets.cmip6 import CMIP6DatasetAdapter -from climate_ref.datasets.obs4mips import Obs4MIPsDatasetAdapter +from climate_ref.datasets.obs4mips import Obs4MIPsDatasetAdapter, Obs4REFDatasetAdapter from climate_ref.models import Execution from climate_ref.solve_helpers import load_solve_catalog from climate_ref.solver import solve_executions @@ -220,20 +220,26 @@ def cmip6_data_catalog(sample_data: None, sample_data_dir: Path) -> pd.DataFrame @pytest.fixture(scope="session") def obs4mips_data_catalog(sample_data: None, sample_data_dir: Path) -> pd.DataFrame: """obs4MIPs sample data catalog.""" - adapter = Obs4MIPsDatasetAdapter() - obs4ref = adapter.find_local_datasets(sample_data_dir / "obs4REF") - obs4mips = adapter.find_local_datasets(sample_data_dir / "obs4MIPs") - return pd.concat([obs4ref, obs4mips], ignore_index=True) + return Obs4MIPsDatasetAdapter().find_local_datasets(sample_data_dir / "obs4MIPs") + + +@pytest.fixture(scope="session") +def obs4ref_data_catalog(sample_data: None, sample_data_dir: Path) -> pd.DataFrame: + """obs4REF sample data catalog.""" + return Obs4REFDatasetAdapter().find_local_datasets(sample_data_dir / "obs4REF") @pytest.fixture(scope="session") def data_catalog( - cmip6_data_catalog: pd.DataFrame, obs4mips_data_catalog: pd.DataFrame + cmip6_data_catalog: pd.DataFrame, + obs4mips_data_catalog: pd.DataFrame, + obs4ref_data_catalog: pd.DataFrame, ) -> dict[SourceDatasetType, pd.DataFrame]: - """Provide combined data catalog with CMIP6 and obs4MIPs sources.""" + """Provide combined data catalog with CMIP6, obs4MIPs and obs4REF sources.""" return { SourceDatasetType.CMIP6: cmip6_data_catalog, SourceDatasetType.obs4MIPs: obs4mips_data_catalog, + SourceDatasetType.obs4REF: obs4ref_data_catalog, } diff --git a/packages/climate-ref/src/climate_ref/database.py b/packages/climate-ref/src/climate_ref/database.py index 1c029a230..d32ceb888 100644 --- a/packages/climate-ref/src/climate_ref/database.py +++ b/packages/climate-ref/src/climate_ref/database.py @@ -99,10 +99,10 @@ def _make_readonly_sqlite_url(database_url: str) -> tuple[str, dict[str, Any]]: return database_url, {} if encoded_path.startswith("file:"): - # Already URI form — caller is responsible for any ro/immutable flags. + # Already URI form, so the caller is responsible for any read-only flags. return database_url, {"uri": True} - return f"sqlite:///file:{encoded_path}?mode=ro&immutable=1&uri=true", {"uri": True} + return f"sqlite:///file:{encoded_path}?mode=ro&uri=true", {"uri": True} def _get_database_revision(connection: sqlalchemy.engine.Connection) -> str | None: @@ -469,7 +469,7 @@ def from_config( read_only If True, open the database in read-only mode and skip migrations. - SQLite URLs are rewritten to URI form with ``mode=ro&immutable=1``. + SQLite URLs are rewritten to URI form with ``mode=ro``. For other backends, callers must configure the connecting role as read-only themselves. diff --git a/packages/climate-ref/src/climate_ref/datasets/catalog_builder.py b/packages/climate-ref/src/climate_ref/datasets/catalog_builder.py index 8d6d37d08..941ccd75c 100644 --- a/packages/climate-ref/src/climate_ref/datasets/catalog_builder.py +++ b/packages/climate-ref/src/climate_ref/datasets/catalog_builder.py @@ -23,10 +23,28 @@ TRACEBACK = "TRACEBACK" +def _walk_sorted(root: Path) -> Iterator[tuple[str, list[str]]]: + """ + Walk ``root``, descending into subdirectories in sorted order. + + Parameters + ---------- + root + Directory to walk. + + Yields + ------ + : + The directory path and the names of the files directly inside it. + """ + for dirpath, dirnames, filenames in os.walk(root): + dirnames.sort() + yield dirpath, filenames + + def discover_files( paths: list[str], include_patterns: list[str] | None = None, - depth: int = 0, ) -> list[str]: """ Discover files matching the given glob patterns within the specified paths @@ -38,9 +56,6 @@ def discover_files( include_patterns Glob patterns to include (e.g. ``["*.nc"]``). Defaults to ``["*"]`` if not provided. - depth - Maximum directory depth below each root to search. - ``0`` means only files directly inside the root directory. Returns ------- @@ -60,12 +75,7 @@ def discover_files( assets.append(str(root)) continue - for dirpath, dirnames, filenames in os.walk(root): - current_depth = len(Path(dirpath).relative_to(root).parts) - if current_depth >= depth: - # Still process files at this level, but don't descend further - dirnames.clear() - + for dirpath, filenames in _walk_sorted(root): for filename in filenames: if any(fnmatch.fnmatch(filename, pat) for pat in include_patterns): assets.append(os.path.join(dirpath, filename)) @@ -155,7 +165,6 @@ def build_catalog( paths: list[str], parsing_func: DatasetParsingFunction, include_patterns: list[str] | None = None, - depth: int = 0, n_jobs: int = 1, ) -> pd.DataFrame: """ @@ -173,8 +182,6 @@ def build_catalog( Must return a dict with an ``INVALID_ASSET`` key on failure. include_patterns Glob patterns to include (e.g. ``["*.nc"]``) - depth - Maximum directory depth to search n_jobs Number of parallel workers for parsing. ``1`` = sequential, ``-1`` = all CPUs, ``>1`` = that many worker processes. @@ -189,7 +196,7 @@ def build_catalog( ValueError If no files matching the include patterns are found in the specified paths """ - assets = discover_files(paths, include_patterns=include_patterns, depth=depth) + assets = discover_files(paths, include_patterns=include_patterns) if not assets: raise ValueError(f"No files matching {include_patterns} found in {paths}") @@ -208,7 +215,6 @@ def build_catalog( def iter_discovered_chunks( paths: list[str], include_patterns: list[str] | None = None, - depth: int = 0, chunk_size: int = 10_000, ) -> Iterator[list[str]]: """ @@ -225,8 +231,6 @@ def iter_discovered_chunks( include_patterns Glob patterns to include (e.g. ``["*.nc"]``). Defaults to ``["*"]``. - depth - Maximum directory depth below each root to search. chunk_size Soft target for the number of files per batch. A batch may exceed this if a single directory contains more matching files. @@ -257,12 +261,7 @@ def _flush() -> Iterator[list[str]]: yield from _flush() continue - for dirpath, dirnames, filenames in os.walk(root): - dirnames.sort() - current_depth = len(Path(dirpath).relative_to(root).parts) - if current_depth >= depth: - dirnames.clear() - + for dirpath, filenames in _walk_sorted(root): matched = [ os.path.join(dirpath, fn) for fn in filenames @@ -296,11 +295,10 @@ def _filter_invalid_rows(df: pd.DataFrame) -> pd.DataFrame: return df[df[INVALID_ASSET].isnull()].drop(columns=[INVALID_ASSET, TRACEBACK]) -def iter_built_catalogs( # noqa: PLR0913 +def iter_built_catalogs( paths: list[str], parsing_func: DatasetParsingFunction, include_patterns: list[str] | None = None, - depth: int = 0, n_jobs: int = 1, chunk_size: int = 10_000, ) -> Iterator[pd.DataFrame]: @@ -319,8 +317,6 @@ def iter_built_catalogs( # noqa: PLR0913 Must return a dict with an ``INVALID_ASSET`` key on failure. include_patterns Glob patterns to include (e.g. ``["*.nc"]``). - depth - Maximum directory depth to search. n_jobs Number of parallel workers per chunk for parsing. chunk_size @@ -334,7 +330,7 @@ def iter_built_catalogs( # noqa: PLR0913 """ any_emitted = False for chunk_paths in iter_discovered_chunks( - paths, include_patterns=include_patterns, depth=depth, chunk_size=chunk_size + paths, include_patterns=include_patterns, chunk_size=chunk_size ): logger.info(f"Parsing chunk of {len(chunk_paths)} files") entries = parse_files(chunk_paths, parsing_func, n_jobs=n_jobs) @@ -349,4 +345,4 @@ def iter_built_catalogs( # noqa: PLR0913 yield df if not any_emitted: - logger.info(f"No valid files found in {paths} matching {include_patterns}") + logger.warning(f"No valid files found in {paths} matching {include_patterns}") diff --git a/packages/climate-ref/src/climate_ref/datasets/cmip6.py b/packages/climate-ref/src/climate_ref/datasets/cmip6.py index 6465881df..a54bb4990 100644 --- a/packages/climate-ref/src/climate_ref/datasets/cmip6.py +++ b/packages/climate-ref/src/climate_ref/datasets/cmip6.py @@ -235,7 +235,6 @@ def find_local_datasets(self, file_or_directory: Path) -> pd.DataFrame: paths=[str(file_or_directory)], parsing_func=parsing_function, include_patterns=["*.nc"], - depth=10, n_jobs=self.n_jobs, ) @@ -272,7 +271,6 @@ def iter_local_datasets( paths=[str(file_or_directory)], parsing_func=parsing_function, include_patterns=["*.nc"], - depth=10, n_jobs=self.n_jobs, chunk_size=chunk_size, ): diff --git a/packages/climate-ref/src/climate_ref/datasets/cmip7.py b/packages/climate-ref/src/climate_ref/datasets/cmip7.py index 73779aad3..b112a6e4d 100644 --- a/packages/climate-ref/src/climate_ref/datasets/cmip7.py +++ b/packages/climate-ref/src/climate_ref/datasets/cmip7.py @@ -280,7 +280,6 @@ def find_local_datasets(self, file_or_directory: Path) -> pd.DataFrame: paths=[str(file_or_directory)], parsing_func=parsing_function, include_patterns=["*.nc"], - depth=10, n_jobs=self.n_jobs, ) @@ -317,7 +316,6 @@ def iter_local_datasets( paths=[str(file_or_directory)], parsing_func=parsing_function, include_patterns=["*.nc"], - depth=10, n_jobs=self.n_jobs, chunk_size=chunk_size, ): diff --git a/packages/climate-ref/src/climate_ref/datasets/esmvaltool_reference.py b/packages/climate-ref/src/climate_ref/datasets/esmvaltool_reference.py index fc076130a..c8d027c84 100644 --- a/packages/climate-ref/src/climate_ref/datasets/esmvaltool_reference.py +++ b/packages/climate-ref/src/climate_ref/datasets/esmvaltool_reference.py @@ -103,7 +103,6 @@ def find_local_datasets(self, file_or_directory: Path) -> pd.DataFrame: paths=[str(file_or_directory)], parsing_func=parse_esmvaltool_reference, include_patterns=["*.nc"], - depth=10, n_jobs=self.n_jobs, ) if datasets.empty: diff --git a/packages/climate-ref/src/climate_ref/datasets/obs4mips.py b/packages/climate-ref/src/climate_ref/datasets/obs4mips.py index 71e4d8dcc..4e944f150 100644 --- a/packages/climate-ref/src/climate_ref/datasets/obs4mips.py +++ b/packages/climate-ref/src/climate_ref/datasets/obs4mips.py @@ -1,6 +1,5 @@ from __future__ import annotations -import functools import traceback from pathlib import Path from typing import Any @@ -21,25 +20,36 @@ from climate_ref.models.dataset import Dataset, Obs4MIPsDataset, Obs4REFDataset -def parse_obs4mips( - file: str, accepted_activity_ids: tuple[str, ...] = ("obs4MIPs", "obs4REF"), **kwargs: Any -) -> dict[str, Any]: +def in_collection_directory(paths: pd.Series, activity_id: str) -> pd.Series: """ - Parser for obs4mips + Whether each file sits under the named collection's directory. + + Parameters + ---------- + paths + File paths from a catalog. + activity_id + The collection to look for, ``obs4MIPs`` or ``obs4REF``. + + Returns + ------- + : + A boolean mask over ``paths``. + """ + return paths.astype(str).str.replace("\\", "/", regex=False).str.contains(f"/{activity_id}/", regex=False) + + +def parse_obs4mips(file: str, **kwargs: Any) -> dict[str, Any]: + """ + Parser for obs4MIPs and obs4REF files + + obs4REF files follow the obs4MIPs metadata conventions, so the same parser reads both. + The adapter that called the parser decides which collection the file belongs to. Parameters ---------- file File to parse - accepted_activity_ids - Activity ids that the calling adapter expects. - - Any file whose ``activity_id`` is outside this set but is still a - known obs4MIPs/obs4REF activity id is ingested anyway with a warning - (a REF-curated obs4REF file parsed by the obs4MIPs adapter, or vice versa) -- - the hard-reject cutover for this cross-contamination case is a tracked follow-up, - not this change. A file whose ``activity_id`` is neither ``obs4MIPs`` nor - ``obs4REF`` at all is never a valid asset for this parser and is always rejected. kwargs Additional keyword arguments (not used, but required for protocol compatibility) """ @@ -65,19 +75,11 @@ def parse_obs4mips( try: with netCDF4.Dataset(file, "r") as ds: - # obs4REF is the REF-specific observational product. - # it shares the obs4MIPs metadata conventions and is ingested through this adapter. activity_id = getattr(ds, "activity_id", "") if activity_id not in ("obs4MIPs", "obs4REF"): traceback_message = f"{file} is not an obs4MIPs or obs4REF dataset" raise TypeError(traceback_message) - if activity_id not in accepted_activity_ids: - logger.warning( - f"{file} has activity_id={activity_id!r}, which is outside the expected " - f"{accepted_activity_ids} for this adapter; ingesting anyway" - ) - global_attrs = read_global_attrs(ds, keys) missing_fields = [key for key in keys if global_attrs.get(key) is None] @@ -130,16 +132,12 @@ class Obs4MIPsDatasetAdapter(DatasetAdapter): dataset_cls: type[Dataset] = Obs4MIPsDataset slug_column = "instance_id" - instance_id_prefix = "obs4MIPs" - """Prefix used to build ``instance_id`` for datasets ingested through this adapter.""" - - accepted_activity_ids: tuple[str, ...] = ("obs4MIPs",) + activity_id = "obs4MIPs" """ - Activity ids this adapter expects to ingest. + The collection this adapter ingests into, whatever the file itself claims. - A file whose ``activity_id`` is outside this set (but is still a recognised - obs4MIPs/obs4REF activity id) is ingested anyway with a warning -- see - :func:`parse_obs4mips`. + The obs4REF collection republishes obs4MIPs files unchanged, + so the file attribute cannot tell the two collections apart. """ dataset_specific_metadata = ( @@ -199,15 +197,17 @@ def find_local_datasets(self, file_or_directory: Path) -> pd.DataFrame: """ datasets = build_catalog( paths=[str(file_or_directory)], - parsing_func=functools.partial(parse_obs4mips, accepted_activity_ids=self.accepted_activity_ids), + parsing_func=parse_obs4mips, include_patterns=["*.nc"], - depth=10, n_jobs=self.n_jobs, ) if datasets.empty: logger.error("No datasets found") raise ValueError("No obs4MIPs-compliant datasets found") + self._warn_if_misfiled(datasets) + datasets["activity_id"] = self.activity_id + # Convert the start_time and end_time columns to cftime objects datasets["start_time"] = parse_cftime_dates(datasets["start_time"]) datasets["end_time"] = parse_cftime_dates(datasets["end_time"]) @@ -220,22 +220,38 @@ def find_local_datasets(self, file_or_directory: Path) -> pd.DataFrame: def _transform(item: str, value: Any) -> str: return str(value).replace(" ", "") if item == "nominal_resolution" else str(value) - datasets = build_instance_id( - datasets, drs_items, prefix=self.instance_id_prefix, transform=_transform - ) + datasets = build_instance_id(datasets, drs_items, prefix=self.activity_id, transform=_transform) datasets["finalised"] = True return datasets + def _warn_if_misfiled(self, datasets: pd.DataFrame) -> None: + """ + Warn when the files look like they belong to the other collection. + + The registry republishes obs4MIPs files unchanged, so an ``obs4REF`` directory + or activity id is only a hint. The files are ingested either way. + """ + other = "obs4REF" if self.activity_id == "obs4MIPs" else "obs4MIPs" + misfiled = in_collection_directory(datasets["path"], other) + if other == "obs4REF": + # An obs4MIPs attribute on an obs4REF file is expected, the reverse is not. + misfiled |= datasets["activity_id"] == other + count = int(misfiled.sum()) + if count: + logger.warning( + f"{count} of {len(datasets)} files look like {other} data but are being ingested as " + f"{self.activity_id}. Use `--source-type {other.lower()}` if that is not intended." + ) + class Obs4REFDatasetAdapter(Obs4MIPsDatasetAdapter): """ Adapter for obs4REF datasets - obs4REF is REF-curated observational data that shares the obs4MIPs metadata - conventions and is parsed by the same :func:`parse_obs4mips` function, but is - ingested as a distinct dataset type so it is never mistaken for published obs4MIPs data. + obs4REF is the REF-curated collection of observational data. + It shares the obs4MIPs metadata conventions and parser, + but is ingested as its own dataset type so it is never mistaken for published obs4MIPs data. """ dataset_cls: type[Dataset] = Obs4REFDataset - instance_id_prefix = "obs4REF" - accepted_activity_ids: tuple[str, ...] = ("obs4REF",) + activity_id = "obs4REF" diff --git a/packages/climate-ref/src/climate_ref/doctor/checks/data.py b/packages/climate-ref/src/climate_ref/doctor/checks/data.py index 79e83db56..472ba277e 100644 --- a/packages/climate-ref/src/climate_ref/doctor/checks/data.py +++ b/packages/climate-ref/src/climate_ref/doctor/checks/data.py @@ -4,15 +4,34 @@ These look for the conditions that make a solve quietly do the wrong thing rather than fail: reference data that no diagnostic can reach, reference data that is missing so its diagnostics never run, -and datasets whose files cover the same period twice. +obs4REF data ingested under the obs4MIPs source type, +obs4REF data that obs4MIPs has since published, +datasets whose files cover the same period twice, +and diagnostics the ingested data cannot solve at all. """ from collections import defaultdict +from collections.abc import Iterable, Mapping +import pandas as pd + +from climate_ref.data_catalog import DataCatalog +from climate_ref.datasets.obs4mips import in_collection_directory from climate_ref.doctor.context import DoctorContext from climate_ref.doctor.findings import Finding, Severity from climate_ref.doctor.registry import check +from climate_ref.solver import ( + apply_obs4ref_fallback, + as_frame, + catalog_for_requirement, + extract_covered_datasets, + solve_executions, + union_with_fallbacks, +) from climate_ref.text import pluralise +from climate_ref_core.diagnostics import Diagnostic +from climate_ref_core.exceptions import InvalidDiagnosticException +from climate_ref_core.providers import DiagnosticProvider from climate_ref_core.reference_data import ( ESGF_OBS4MIPS, ReferenceDataset, @@ -20,7 +39,7 @@ source_ids_by_registry, ) from climate_ref_core.source_types import SourceDatasetType -from climate_ref_core.summary import summarize_provider +from climate_ref_core.summary import normalize_requirement_sets, summarize_provider @check( @@ -92,6 +111,29 @@ def check_duplicate_coverage(context: DoctorContext) -> list[Finding]: return findings +def _declared_fallbacks(providers: Iterable[DiagnosticProvider]) -> dict[str, set[str]]: + """ + Collect the fallback source types the providers' requirements declare. + + Parameters + ---------- + providers + The providers to inspect. + + Returns + ------- + : + Source type values mapped to the source type values that may stand in for them. + """ + declared: dict[str, set[str]] = defaultdict(set) + for provider in providers: + for diagnostic in summarize_provider(provider).diagnostics: + for requirement_set in diagnostic.requirement_sets: + for requirement in requirement_set.requirements: + declared[requirement.source_type].update(requirement.fallback_source_types) + return declared + + def _collection_root(path: str, depth: int = 4) -> str: """Shorten a file path to the directory that identifies which collection it came from.""" parts = str(path).split("/") @@ -129,6 +171,12 @@ def check_missing_reference_data(context: DoctorContext) -> list[Finding]: if len(catalog) and "source_id" in catalog: ingested[source_type.value].update(catalog["source_id"].unique()) + # obs4REF fills in whatever obs4MIPs lacks, so either satisfies an obs4MIPs requirement. + ingested[SourceDatasetType.obs4MIPs.value] |= ingested[SourceDatasetType.obs4REF.value] + for requested_type, fallbacks in _declared_fallbacks(context.providers).items(): + for fallback in fallbacks: + ingested[requested_type] |= ingested[fallback] + findings = [] for dataset in sorted(required, key=lambda d: (d.supplier, d.source_id)): if dataset.source_id in ingested[dataset.source_type]: @@ -179,11 +227,9 @@ def check_unreachable_source_types(context: DoctorContext) -> list[Finding]: """ Find data ingested under a source type that no enabled diagnostic asks for. - The clearest case is obs4REF. - The ``obs4ref`` source type exists and can be ingested, - but no diagnostic declares an obs4REF data requirement, - and the solver only matches a requirement against its own source type. - Data ingested that way is never selected. + The solver only matches a requirement against its own source type, + so data ingested under a type nothing asks for is never selected. + The one exception is obs4REF data, which fills in for obs4MIPs requirements. Parameters ---------- @@ -201,6 +247,9 @@ def check_unreachable_source_types(context: DoctorContext) -> list[Finding]: for requirement_set in diagnostic.requirement_sets: for requirement in requirement_set.requirements: requested.add(requirement.source_type) + requested.update(requirement.fallback_source_types) + if SourceDatasetType.obs4MIPs.value in requested: + requested.add(SourceDatasetType.obs4REF.value) findings = [] for source_type in SourceDatasetType: @@ -222,14 +271,193 @@ def check_unreachable_source_types(context: DoctorContext) -> list[Finding]: "so nothing will select these datasets." ), remedy=( - "If this is obs4REF data, re-ingest it with " - f"`--source-type {SourceDatasetType.obs4MIPs.value}`." + "Re-ingest the data under the source type the diagnostics ask for, " + "or enable a provider that uses it." ), ) ) return findings +@check( + "misfiled-obs4ref", + "obs4REF data ingested under the obs4MIPs source type", +) +def check_misfiled_obs4ref(context: DoctorContext) -> list[Finding]: + """ + Find obs4REF data that was ingested as obs4MIPs. + + Earlier releases ingested the obs4REF collection this way, and it still solves. + The cost is that the catalog no longer shows which datasets came from the registry + and which from the archive, and a later obs4MIPs publication cannot take over from it. + + A dataset counts as obs4REF when its files sit under an ``obs4REF`` directory, + which is how the registry lays them out. + Carrying a ``source_id`` the registry also carries is not enough, + because the four datasets published to both archives are legitimately ingested as obs4MIPs. + The file's own ``activity_id`` is stamped from the source type at ingest, + so only the ingest-time warning can use it. + + Parameters + ---------- + context + The deployment to check. + + Returns + ------- + : + One finding per misfiled dataset, all sharing the one remedy. + """ + catalog = context.catalog(SourceDatasetType.obs4MIPs) + if not len(catalog) or not {"instance_id", "path"}.issubset(catalog.columns): + return [] + + misfiled = in_collection_directory(catalog["path"], "obs4REF") + if not misfiled.any(): + return [] + + return [ + Finding( + severity=Severity.WARNING, + summary=f"{instance_id} is obs4REF data ingested as obs4mips", + remedy=( + "Re-ingest the obs4REF collection under its own source type, " + "then retract each of the obs4mips rows above with `ref datasets retract `." + ), + command="ref datasets ingest --source-type obs4ref ", + ) + for instance_id in sorted(catalog.loc[misfiled, "instance_id"].unique()) + ] + + +@check( + "superseded-obs4ref", + "obs4REF datasets that the obs4MIPs archive has since published", +) +def check_superseded_obs4ref(context: DoctorContext) -> list[Finding]: + """ + Find obs4REF datasets that lose to an ingested obs4MIPs copy. + + The solver takes the newest version, and the obs4MIPs copy on a tie, so these rows are never used. + This is the signal that a dataset can be dropped from the obs4REF registry. + + Parameters + ---------- + context + The deployment to check. + + Returns + ------- + : + One finding per superseded obs4REF dataset. + """ + obs4mips = context.catalog(SourceDatasetType.obs4MIPs) + obs4ref = context.catalog(SourceDatasetType.obs4REF) + if not len(obs4mips) or not len(obs4ref) or "instance_id" not in obs4mips or "instance_id" not in obs4ref: + return [] + + genuine = obs4mips + if "path" in obs4mips.columns: + genuine = obs4mips[~in_collection_directory(obs4mips["path"], "obs4REF")] + if not len(genuine): + return [] + + used = set(as_frame(union_with_fallbacks(genuine, [obs4ref], SourceDatasetType.obs4MIPs))["instance_id"]) + superseded = obs4ref[~obs4ref["instance_id"].isin(used)] + return [ + Finding( + severity=Severity.INFO, + summary=f"{instance_id} is superseded by the obs4MIPs copy", + remedy=( + "The obs4MIPs copy is the same or a newer version, so it is used instead. " + "These can be retracted, and dropped from the obs4REF registry." + ), + ) + for instance_id in sorted(superseded["instance_id"].unique()) + ] + + +@check( + "unsolvable-diagnostics", + "Enabled diagnostics for which the ingested data produces no executions", +) +def check_unsolvable_diagnostics(context: DoctorContext) -> list[Finding]: + """ + Find enabled diagnostics that the ingested data cannot solve at all. + + This runs the solver against the ingested catalogs, diagnostic by diagnostic, + so it catches everything the narrower checks do not: + + - a filter no dataset matches + - a constraint no group satisfies + - a source type nothing was ingested under + + Parameters + ---------- + context + The deployment to check. + + Returns + ------- + : + One finding per diagnostic with no executions. + """ + catalogs: dict[SourceDatasetType, DataCatalog] = { + source_type: context.data_catalog(source_type) for source_type in SourceDatasetType + } + + available = apply_obs4ref_fallback(catalogs) + + findings = [] + for provider in context.providers: + for diagnostic in provider.diagnostics(): + try: + solvable = any(True for _ in solve_executions(catalogs, diagnostic, provider)) + except (InvalidDiagnosticException, ValueError): + # ValueError is a diagnostic declaring no data requirements at all. + solvable = False + if solvable: + continue + findings.append( + Finding( + severity=Severity.WARNING, + summary=f"{provider.slug}/{diagnostic.slug} has no executions", + detail=_why_unsolvable(diagnostic, available), + remedy="Ingest the data the unmet requirement names, then run the solver again.", + ) + ) + return findings + + +def _why_unsolvable( + diagnostic: Diagnostic, + available: Mapping[SourceDatasetType, pd.DataFrame | DataCatalog], +) -> str: + """ + Explain which requirement the ingested data fails to meet. + + Each requirement is checked on its own, so the first one with no matching group names the data to fetch. + When every requirement matches something, the failure lies in how they combine, which is reported as such. + """ + reasons = [] + for requirements in normalize_requirement_sets(diagnostic.data_requirements): + for requirement in requirements: + catalog = catalog_for_requirement(available, requirement) + if catalog is None or not len(as_frame(catalog)): + reasons.append(f"nothing is ingested as {requirement.source_type.value}") + break + if not extract_covered_datasets(catalog, requirement): + facets = " and ".join( + ", ".join(f"{k}={'|'.join(v)}" for k, v in sorted(f.facets.items())) + for f in requirement.filters + ) + reasons.append(f"no {requirement.source_type.value} datasets match {facets}") + break + else: + reasons.append("every requirement matches data, but no complete group satisfies the constraints") + return "Unmet: " + ". ".join(dict.fromkeys(reasons)) + "." + + @check( "overlapping-registries", "Reference datasets that more than one registry carries", diff --git a/packages/climate-ref/src/climate_ref/doctor/context.py b/packages/climate-ref/src/climate_ref/doctor/context.py index 59183a44a..e8ca97d6b 100644 --- a/packages/climate-ref/src/climate_ref/doctor/context.py +++ b/packages/climate-ref/src/climate_ref/doctor/context.py @@ -8,6 +8,7 @@ from attrs import define, field from climate_ref.config import Config +from climate_ref.data_catalog import DataCatalog from climate_ref.database import Database from climate_ref.datasets import get_dataset_adapter from climate_ref_core.providers import DiagnosticProvider @@ -74,6 +75,28 @@ def providers(self) -> list[DiagnosticProvider]: self._providers = list(registry.providers) return self._providers + def data_catalog(self, source_type: SourceDatasetType) -> DataCatalog: + """ + Load the ingested catalog as the solver sees it. + + The adapter and database are carried through where there are any, + so an unfinalised dataset can still be finalised during a solve. + + Parameters + ---------- + source_type + The source type to load. + + Returns + ------- + : + A catalog the solver can be run against. + """ + frame = self.catalog(source_type) + if self.database is None: + return DataCatalog.from_frame(frame) + return DataCatalog(database=self.database, adapter=get_dataset_adapter(source_type.value), df=frame) + def catalog(self, source_type: SourceDatasetType) -> pd.DataFrame: """ Load the ingested catalog for a source type, one row per file. diff --git a/packages/climate-ref/src/climate_ref/solver.py b/packages/climate-ref/src/climate_ref/solver.py index 68e5144da..ee3fd82a0 100644 --- a/packages/climate-ref/src/climate_ref/solver.py +++ b/packages/climate-ref/src/climate_ref/solver.py @@ -40,6 +40,7 @@ ExecutionDatasetCollection, Selector, SourceDatasetType, + version_sort_key, ) from climate_ref_core.diagnostics import DataRequirement, Diagnostic, ExecutionDefinition from climate_ref_core.exceptions import InvalidDiagnosticException @@ -248,6 +249,155 @@ def _process_group_constraints( return group +def as_frame(catalog: pd.DataFrame | DataCatalog) -> pd.DataFrame: + """ + Unwrap a catalog to the DataFrame behind it. + + Parameters + ---------- + catalog + Either a catalog wrapper or a plain frame. + + Returns + ------- + : + The catalog as a DataFrame. + """ + return catalog.to_frame() if isinstance(catalog, DataCatalog) else catalog + + +def union_with_fallbacks( + primary: pd.DataFrame | DataCatalog, + fallbacks: Sequence[pd.DataFrame | DataCatalog], + primary_type: SourceDatasetType, +) -> pd.DataFrame | DataCatalog: + """ + Fill a reference catalog from its fallback collections. + + A dataset held by more than one collection is taken at its newest version, + and from the primary when the versions tie. + So publishing a dataset to obs4MIPs takes over from the obs4REF copy without any re-ingest, + but a newer registry version is not lost to a stale published one. + + Parameters + ---------- + primary + The catalog the requirement asks for, which wins a version tie. + fallbacks + Catalogs that may stand in for it, tried in order. + primary_type + Source type the merged rows are delivered under. + + Returns + ------- + : + The primary catalog, extended with the fallback rows that win. + The original catalog is returned untouched when nothing is added. + The added rows carry ``activity_id`` of the primary, because that is the collection they stand in for. + Their ``instance_id`` still names the collection they came from, so the provenance is not lost. + """ + usable = [ + frame + for frame in (as_frame(fallback) for fallback in fallbacks) + if not frame.empty and "instance_id" in frame.columns + ] + if not usable: + return primary + + merged = as_frame(primary) + if len(merged) and "instance_id" not in merged.columns: + return primary + changed = False + for fallback_df in usable: + taken = newer_rows(fallback_df, merged) + if taken.empty: + continue + # The rows are served as the primary's data, so they must group as the primary's data too. + # A requirement grouping by activity_id would otherwise split its reference data in two. + if "activity_id" in taken.columns: + taken = taken.assign(activity_id=primary_type.name) + if len(merged): + beaten = _obs_dataset_key(merged["instance_id"]).isin(_obs_dataset_key(taken["instance_id"])) + merged = pd.concat([merged[~beaten], taken], ignore_index=True) + else: + merged = taken.reset_index(drop=True) + changed = True + + if not changed: + return primary + if isinstance(primary, DataCatalog) or any(isinstance(f, DataCatalog) for f in fallbacks): + # No adapter can reload the merge, so the result carries none and never reloads. + return DataCatalog.from_frame(merged) + return merged + + +def _obs_dataset_version(instance_id: pd.Series) -> pd.Series: + """Read the numeric version key off the end of an obs4MIPs or obs4REF ``instance_id``.""" + return instance_id.astype(str).str.rsplit(".", n=1).str[1].map(version_sort_key) + + +def _obs_dataset_key(instance_id: pd.Series) -> pd.Series: + """Strip the collection prefix to be common between obs4MIPs or obs4REF""" + return instance_id.astype(str).str.split(".", n=2).str[2].str.rsplit(".", n=1).str[0] + + +def newer_rows(candidate: pd.DataFrame, held: pd.DataFrame) -> pd.DataFrame: + """ + Select the rows of ``candidate`` that ``held`` lacks, or holds at an older version. + + Parameters + ---------- + candidate + Rows offered by a fallback collection. + held + Rows already taken, which win a version tie. + + Returns + ------- + : + The subset of ``candidate`` that should replace or extend ``held``. + """ + if not len(held): + return candidate + held_version = pd.Series( + _obs_dataset_version(held["instance_id"]).to_numpy(), + index=_obs_dataset_key(held["instance_id"]).to_numpy(), + ) + held_version = held_version.groupby(level=0).max() + current = _obs_dataset_key(candidate["instance_id"]).map(held_version) + wins = current.isna() | (_obs_dataset_version(candidate["instance_id"]) > current) + return candidate[wins] + + +def apply_obs4ref_fallback( + data_catalog: Mapping[SourceDatasetType, pd.DataFrame | DataCatalog], +) -> Mapping[SourceDatasetType, pd.DataFrame | DataCatalog]: + """ + Fold the obs4REF catalog into the obs4MIPs one so obs4MIPs requirements can reach it. + + Parameters + ---------- + data_catalog + Data catalogs for each source dataset type + + Returns + ------- + : + The catalogs with obs4MIPs extended by the obs4REF datasets it lacks + (see `union_with_fallbacks`). + The mapping is returned unchanged when nothing is ingested as obs4REF. + """ + if SourceDatasetType.obs4REF not in data_catalog: + return data_catalog + obs4mips = data_catalog.get(SourceDatasetType.obs4MIPs, pd.DataFrame()) + return { + **data_catalog, + SourceDatasetType.obs4MIPs: union_with_fallbacks( + obs4mips, [data_catalog[SourceDatasetType.obs4REF]], SourceDatasetType.obs4MIPs + ), + } + + def solve_executions( data_catalog: Mapping[SourceDatasetType, pd.DataFrame | DataCatalog], diagnostic: Diagnostic, @@ -275,11 +425,12 @@ def solve_executions( raise ValueError(f"Diagnostic {diagnostic.slug!r} has no data requirements") first_item = next(iter(diagnostic.data_requirements)) + catalogs = apply_obs4ref_fallback(data_catalog) if isinstance(first_item, DataRequirement): # We have a single collection of data requirements yield from _solve_from_data_requirements( - data_catalog, + catalogs, diagnostic, typing.cast(Sequence[DataRequirement], diagnostic.data_requirements), provider, @@ -294,7 +445,7 @@ def solve_executions( # Buffer executions to check if any were actually produced # _solve_from_data_requirements returns empty if source types are missing executions = list( - _solve_from_data_requirements(data_catalog, diagnostic, requirement_collection, provider) + _solve_from_data_requirements(catalogs, diagnostic, requirement_collection, provider) ) if executions: any_matched = True @@ -310,6 +461,40 @@ def solve_executions( raise TypeError(f"Expected a DataRequirement, got {type(first_item)}") +def catalog_for_requirement( + data_catalog: Mapping[SourceDatasetType, pd.DataFrame | DataCatalog], + requirement: DataRequirement, +) -> pd.DataFrame | DataCatalog | None: + """ + Resolve the catalog a requirement is solved against, folding in its declared fallbacks. + + Parameters + ---------- + data_catalog + Data catalogs for each source dataset type. + requirement + The requirement to resolve a catalog for. + + Returns + ------- + : + The requirement's catalog, or ``None`` when neither it nor any of its fallbacks + has been ingested. + """ + fallbacks = [ + data_catalog[source_type] + for source_type in requirement.fallback_source_types + if source_type in data_catalog + ] + if requirement.source_type not in data_catalog and not fallbacks: + return None + + primary = data_catalog.get(requirement.source_type, pd.DataFrame()) + if not fallbacks: + return primary + return union_with_fallbacks(primary, fallbacks, requirement.source_type) + + def _solve_from_data_requirements( data_catalog: Mapping[SourceDatasetType, pd.DataFrame | DataCatalog], diagnostic: Diagnostic, @@ -322,16 +507,15 @@ def _solve_from_data_requirements( for requirement in data_requirements: if not isinstance(requirement, DataRequirement): raise TypeError(f"Expected a DataRequirement, got {type(requirement)}") - if requirement.source_type not in data_catalog: + catalog = catalog_for_requirement(data_catalog, requirement) + if catalog is None: logger.debug( f"No data catalog for source type {requirement.source_type} of " f"{provider.slug} diagnostic {diagnostic.slug}" ) return - dataset_groups[requirement.source_type] = extract_covered_datasets( - data_catalog[requirement.source_type], requirement - ) + dataset_groups[requirement.source_type] = extract_covered_datasets(catalog, requirement) # Calculate the product across each of the source types for items in itertools.product(*dataset_groups.values()): diff --git a/packages/climate-ref/tests/unit/baseline_report/__init__.py b/packages/climate-ref/tests/unit/baseline_report/__init__.py new file mode 100644 index 000000000..2111eb203 --- /dev/null +++ b/packages/climate-ref/tests/unit/baseline_report/__init__.py @@ -0,0 +1 @@ +"""Tests for the local baseline diff report.""" diff --git a/packages/climate-ref/tests/unit/baseline_report/test_analyse.py b/packages/climate-ref/tests/unit/baseline_report/test_analyse.py new file mode 100644 index 000000000..3b23bcc21 --- /dev/null +++ b/packages/climate-ref/tests/unit/baseline_report/test_analyse.py @@ -0,0 +1,508 @@ +"""Tests for fetching blobs and building the diffs the templates render.""" + +import json +from unittest.mock import MagicMock + +import numpy as np +import pytest +import xarray as xr +from attrs import evolve + +from climate_ref.baseline_report.analyse import ( + MAX_FETCH_BYTES, + NETCDF_FETCH_BYTES, + analyse, + blob_url, + netcdf_diff, + text_diff, +) +from climate_ref.baseline_report.collect import ( + CaseChange, + FileChange, + FileKind, + Report, + classify, +) +from climate_ref_core.regression.manifest import NativeEntry +from climate_ref_core.regression.store import NativeStore + + +def _kinds(diff): + """Return the kind of every line in a diff.""" + return [line.kind for line in diff.lines] + + +def _file_change(name, old, new): + """Build a file change from two entries.""" + return FileChange(name=name, old=old, new=new, kind=classify(name)) + + +def _report(files): + """Wrap file changes in a single-case report.""" + case = CaseChange( + label="example/diag/case", + rel_path="packages/climate-ref-example/tests/test-data/diag/case/manifest.json", + base=None, + head=None, + files=tuple(files), + committed=(), + metadata=(), + ) + return Report(base_ref="origin/main", head_sha="a" * 40, cases=(case,)) + + +class TestBlobUrl: + def test_a_remote_store_serves_blobs_flat(self): + store = NativeStore(url="https://store/") + + assert blob_url(store, "a" * 64) == f"https://store/{'a' * 64}" + + def test_a_local_store_keeps_its_two_level_fan_out(self, tmp_path): + store = NativeStore(url=str(tmp_path / "store")) + digest = "a" * 64 + + url = blob_url(store, digest) + + assert url.startswith("file://") + assert url.endswith(f"/aa/{digest}") + + +class TestTextDiff: + def test_json_key_order_is_not_a_difference(self, tmp_path): + old = tmp_path / "old.json" + new = tmp_path / "new.json" + old.write_text(json.dumps({"b": 2, "a": 1})) + new.write_text(json.dumps({"a": 1, "b": 2})) + + diff = text_diff(old, new, "series.json") + + assert diff.note == "identical after decoding" + assert diff.lines == () + + def test_one_changed_line(self, tmp_path): + old = tmp_path / "old.csv" + new = tmp_path / "new.csv" + old.write_text("header\nvalue 1\ntail\n") + new.write_text("header\nvalue 2\ntail\n") + + diff = text_diff(old, new, "series.csv") + + assert diff.note is None + kinds = _kinds(diff) + assert kinds.count("add") == 1 + assert kinds.count("remove") == 1 + assert "hunk" in kinds + assert kinds.count("header") == 2 + + def test_added_file_is_all_additions(self, tmp_path): + new = tmp_path / "new.txt" + new.write_text("one\ntwo\n") + + diff = text_diff(None, new, "new.txt") + + assert [line.kind for line in diff.lines if line.kind not in ("header", "hunk")] == [ + "add", + "add", + ] + + +class TestAnalyse: + def test_no_fetch_notes_every_text_file(self, tmp_path): + store = MagicMock(spec=NativeStore) + store.url = "https://store" + store.root = None + report = _report( + [ + _file_change("plot.png", None, NativeEntry(sha256="1" * 64, size=10)), + _file_change("series.json", None, NativeEntry(sha256="2" * 64, size=10)), + ] + ) + + analysed = analyse(report, store, fetch=False, workdir=tmp_path) + + files = {f.change.name: f for f in analysed.cases[0].files} + assert files["series.json"].text.note == "fetching disabled" + assert files["plot.png"].text is None + store.fetch.assert_not_called() + + def test_counts_are_tallied_per_kind(self, tmp_path): + store = MagicMock(spec=NativeStore) + store.url = "https://store" + store.root = None + entry = NativeEntry(sha256="1" * 64, size=10) + other = NativeEntry(sha256="2" * 64, size=10) + report = _report( + [ + _file_change("a.png", None, entry), + _file_change("b.png", entry, other), + _file_change("c.nc", entry, None), + ] + ) + + rows = analyse(report, store, fetch=False, workdir=tmp_path).cases[0].counts + counts = {row.label: row for row in rows} + + assert (counts["image"].added, counts["image"].changed, counts["image"].removed) == (1, 1, 0) + assert (counts["netcdf"].added, counts["netcdf"].changed, counts["netcdf"].removed) == (0, 0, 1) + assert (counts["text"].added, counts["text"].changed, counts["text"].removed) == (0, 0, 0) + # Every kind gets a column, in the enum's order, so the index header cannot drift. + assert [ + row.label for row in analyse(report, store, fetch=False, workdir=tmp_path).cases[0].counts + ] == [kind.value for kind in FileKind] + + def test_partitions_and_back_link(self, tmp_path): + store = MagicMock(spec=NativeStore) + store.url = "https://store" + store.root = None + entry = NativeEntry(sha256="1" * 64, size=10) + report = _report( + [ + _file_change("a.png", None, entry), + _file_change("b.json", None, entry), + _file_change("c.nc", None, entry), + _file_change("d.bin", None, entry), + ] + ) + + case = analyse(report, store, fetch=False, workdir=tmp_path).cases[0] + + assert [f.change.name for f in case.images] == ["a.png"] + assert [f.change.name for f in case.texts] == ["b.json"] + assert [f.change.name for f in case.netcdfs] == ["c.nc"] + assert [f.change.name for f in case.others] == ["d.bin"] + # The label has three segments, so the index sits three levels up. + assert case.back_link == "../../../index.html" + + def test_the_back_link_follows_the_label_depth(self, tmp_path): + store = MagicMock(spec=NativeStore) + store.url = "https://store" + store.root = None + report = _report([]) + shallow = evolve(report.cases[0], label="pmp") + report = evolve(report, cases=(shallow,)) + + case = analyse(report, store, fetch=False, workdir=tmp_path).cases[0] + + assert case.back_link == "../index.html" + + def test_size_delta_is_signed_and_absent_on_one_sided_files(self, tmp_path): + store = MagicMock(spec=NativeStore) + store.url = "https://store" + store.root = None + report = _report( + [ + _file_change( + "grew.png", NativeEntry(sha256="1" * 64, size=10), NativeEntry(sha256="2" * 64, size=25) + ), + _file_change("added.png", None, NativeEntry(sha256="3" * 64, size=25)), + ] + ) + + files = { + f.change.name: f for f in analyse(report, store, fetch=False, workdir=tmp_path).cases[0].files + } + + assert files["grew.png"].size_delta == 15 + assert files["added.png"].size_delta is None + + def test_local_store_produces_a_real_diff(self, tmp_path): + store = NativeStore(url=str(tmp_path / "store")) + old_file = tmp_path / "old.csv" + new_file = tmp_path / "new.csv" + old_file.write_text("a\nb\n") + new_file.write_text("a\nc\n") + old_digest = store.put(old_file) + new_digest = store.put(new_file) + + report = _report( + [ + _file_change( + "series.csv", + NativeEntry(sha256=old_digest, size=old_file.stat().st_size), + NativeEntry(sha256=new_digest, size=new_file.stat().st_size), + ) + ] + ) + + analysed = analyse(report, store, fetch=True, workdir=tmp_path) + + diff = analysed.cases[0].files[0].text + assert diff.note is None + assert [line.text for line in diff.lines if line.kind == "add"] == ["+c"] + assert [line.text for line in diff.lines if line.kind == "remove"] == ["-b"] + + def test_oversized_blob_is_noted_not_fetched(self, tmp_path): + store = MagicMock(spec=NativeStore) + store.url = "https://store" + store.root = None + report = _report( + [ + _file_change( + "big.json", + None, + NativeEntry(sha256="1" * 64, size=MAX_FETCH_BYTES + 1), + ) + ] + ) + + analysed = analyse(report, store, fetch=True, workdir=tmp_path) + + assert "too large to diff" in analysed.cases[0].files[0].text.note + store.fetch.assert_not_called() + + def test_a_failed_fetch_becomes_a_note(self, tmp_path): + store = MagicMock(spec=NativeStore) + store.url = "https://store" + store.root = None + store.fetch.side_effect = FileNotFoundError("gone") + report = _report([_file_change("series.json", None, NativeEntry(sha256="1" * 64, size=10))]) + + analysed = analyse(report, store, fetch=True, workdir=tmp_path) + + assert "could not fetch" in analysed.cases[0].files[0].text.note + + @pytest.mark.parametrize("fetch", [True, False]) + def test_urls_follow_the_entries_that_exist(self, tmp_path, fetch): + store = MagicMock(spec=NativeStore) + store.url = "https://store/" + store.root = None + report = _report([_file_change("plot.png", NativeEntry(sha256="1" * 64, size=10), None)]) + + analysed = analyse(report, store, fetch=fetch, workdir=tmp_path) + + file = analysed.cases[0].files[0] + assert file.old_url == f"https://store/{'1' * 64}" + assert file.new_url is None + assert analysed.store_url == "https://store" + + +def _write_nc(path, data, attrs=None, name="tas"): + """Write a single-variable dataset to a NetCDF file and return its path.""" + values = np.asarray(data) + dataset = xr.Dataset( + {name: (("lat", "lon"), values)}, + coords={"lat": np.arange(values.shape[0], dtype=float), "lon": np.arange(values.shape[1])}, + attrs=attrs or {"title": "a"}, + ) + dataset.to_netcdf(path) + return path + + +@pytest.fixture +def base_nc(tmp_path): + """A two by two dataset both sides of every pair start from.""" + return _write_nc(tmp_path / "old.nc", [[1.0, 2.0], [3.0, 4.0]]) + + +class TestNetcdfDiff: + def test_identical_files_show_the_whole_header_as_context(self, tmp_path, base_nc): + new = _write_nc(tmp_path / "new.nc", [[1.0, 2.0], [3.0, 4.0]]) + + diff = netcdf_diff(base_nc, new) + + assert diff.note is None + assert diff.header_changed is False + assert {line.kind for line in diff.header} == {"context"} + assert len(diff.header) == len(diff.header_old) == len(diff.header_new) + assert diff.rows[0].moved is False + assert diff.rows[0].cells_differ == 0 + assert diff.rows[0].max_abs_diff == 0.0 + + def test_a_changed_attribute_shows_in_the_header_only(self, tmp_path, base_nc): + new = _write_nc(tmp_path / "new.nc", [[1.0, 2.0], [3.0, 4.0]], attrs={"title": "b"}) + + diff = netcdf_diff(base_nc, new) + + assert sum(1 for line in diff.header if line.kind == "add") == 1 + assert sum(1 for line in diff.header if line.kind == "remove") == 1 + assert diff.header_changed is True + assert any(line.kind == "context" for line in diff.header) # the rest is still shown + assert all(row.moved is False for row in diff.rows) + + def test_one_changed_value_is_counted_and_measured(self, tmp_path, base_nc): + new = _write_nc(tmp_path / "new.nc", [[1.0, 2.0], [3.0, 4.5]]) + + row = netcdf_diff(base_nc, new).rows[0] + + assert row.cells_differ == 1 + assert row.max_abs_diff == pytest.approx(0.5) + assert row.max_rel_diff == pytest.approx(0.125) + assert row.moved is True + assert row.differs is True + assert row.maximum.changed is True # 4.0 -> 4.5 + assert row.minimum.changed is False + + def test_a_changed_shape_cannot_be_compared_cell_by_cell(self, tmp_path, base_nc): + new = _write_nc(tmp_path / "new.nc", [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]) + + row = netcdf_diff(base_nc, new).rows[0] + + assert row.max_abs_diff is None + assert row.cells_differ is None + assert row.shape.old == "2x2" + assert row.shape.new == "2x3" + assert row.shape.changed is True + assert row.moved is True + + def test_a_nan_in_the_same_cell_on_both_sides_is_not_a_change(self, tmp_path): + old = _write_nc(tmp_path / "old.nc", [[1.0, np.nan], [3.0, 4.0]]) + new = _write_nc(tmp_path / "new.nc", [[1.0, np.nan], [3.0, 4.0]]) + + row = netcdf_diff(old, new).rows[0] + + assert row.cells_differ == 0 + assert row.moved is False + assert row.nan.old == 1 + assert row.nan.new == 1 + assert row.nan.changed is False + + def test_an_all_nan_array_reports_no_statistics(self, tmp_path): + old = _write_nc(tmp_path / "old.nc", [[np.nan, np.nan], [np.nan, np.nan]]) + new = _write_nc(tmp_path / "new.nc", [[np.nan, np.nan], [np.nan, np.nan]]) + + row = netcdf_diff(old, new).rows[0] + + assert (row.minimum.old, row.maximum.old, row.mean.old) == (None, None, None) + assert row.nan.old == 4 + assert row.moved is False + + def test_an_absent_old_side_leaves_every_old_statistic_unset(self, tmp_path, base_nc): + diff = netcdf_diff(None, base_nc) + row = diff.rows[0] + + assert diff.header_old == () + assert diff.header_new + + assert (row.shape.old, row.minimum.old, row.maximum.old, row.mean.old, row.nan.old) == ( + None, + None, + None, + None, + None, + ) + assert row.shape.new == "2x2" + assert row.shape.changed is True + assert row.moved is True + + def test_adjacent_integers_past_the_float_mantissa_still_compare(self, tmp_path): + # 2**53 and the next integer collide once cast to float64. + old_values = np.array([[9007199254740992, 1], [2, 3]], dtype=np.int64) + new_values = np.array([[9007199254740993, 1], [2, 3]], dtype=np.int64) + paths = [] + for name, values in (("old.nc", old_values), ("new.nc", new_values)): + path = tmp_path / name + xr.Dataset({"count": (("lat", "lon"), values)}).to_netcdf(path) + paths.append(path) + + row = netcdf_diff(*paths).rows[0] + + assert row.cells_differ == 1 + assert row.moved is True + + @pytest.mark.parametrize( + ("old_cell", "new_cell"), + [(np.nan, 5.0), (5.0, np.nan)], + ids=["nan_to_number", "number_to_nan"], + ) + def test_a_cell_moving_between_nan_and_a_number_has_no_measurable_difference( + self, tmp_path, old_cell, new_cell + ): + old = _write_nc(tmp_path / "old.nc", [[old_cell, 1.0], [2.0, 3.0]]) + new = _write_nc(tmp_path / "new.nc", [[new_cell, 1.0], [2.0, 3.0]]) + + row = netcdf_diff(old, new).rows[0] + + assert row.cells_differ == 1 + assert row.max_abs_diff is None # never 0.0, which would read as no change + assert row.max_rel_diff is None + assert row.moved is True + + def test_a_file_that_decodes_to_too_much_is_not_reduced(self, tmp_path, base_nc, monkeypatch): + monkeypatch.setattr("climate_ref.baseline_report.analyse.MAX_DECODED_BYTES", 8) + + diff = netcdf_diff(base_nc, base_nc) + + assert diff.note.startswith("decodes to too much to analyse") + assert diff.rows == () + + def test_a_file_that_is_not_netcdf_becomes_a_note(self, tmp_path, base_nc): + broken = tmp_path / "broken.nc" + broken.write_text("not a netcdf file at all") + + diff = netcdf_diff(base_nc, broken) + + assert diff.note.startswith("could not open") + assert diff.rows == () + assert diff.header_old == () + + def test_a_string_variable_gets_shapes_but_no_statistics(self, tmp_path): + for path in (tmp_path / "old.nc", tmp_path / "new.nc"): + xr.Dataset({"label": (("i",), np.array(["a", "b"], dtype=object))}).to_netcdf(path) + + row = netcdf_diff(tmp_path / "old.nc", tmp_path / "new.nc").rows[0] + + assert row.shape.old == "2" + assert row.shape.new == "2" + assert (row.minimum.old, row.maximum.old, row.nan.old, row.cells_differ) == ( + None, + None, + None, + None, + ) + assert row.moved is False + + def test_a_variable_added_on_one_side_only_moves(self, tmp_path, base_nc): + new = tmp_path / "new.nc" + xr.Dataset( + { + "tas": (("lat", "lon"), np.array([[1.0, 2.0], [3.0, 4.0]])), + "pr": (("lat", "lon"), np.array([[0.0, 0.0], [0.0, 0.0]])), + }, + coords={"lat": np.arange(2, dtype=float), "lon": np.arange(2)}, + attrs={"title": "a"}, + ).to_netcdf(new) + + rows = {row.name: row for row in netcdf_diff(base_nc, new).rows} + + assert sorted(rows) == ["pr", "tas"] + assert rows["pr"].moved is True + assert rows["pr"].shape.old is None + assert rows["tas"].moved is False + + +class TestAnalyseNetcdf: + def test_a_netcdf_file_is_fetched_and_analysed(self, tmp_path, base_nc): + store = MagicMock(spec=NativeStore) + store.url = "https://store" + store.root = None + store.fetch.side_effect = lambda digest, dest: dest.write_bytes(base_nc.read_bytes()) + entry = NativeEntry(sha256="1" * 64, size=base_nc.stat().st_size) + report = _report([_file_change("out.nc", entry, evolve(entry, sha256="2" * 64))]) + + file = analyse(report, store, fetch=True, workdir=tmp_path).cases[0].files[0] + + assert file.netcdf.note is None + assert [row.name for row in file.netcdf.rows] == ["tas"] + assert file.text is None + + def test_an_oversized_netcdf_file_is_not_fetched(self, tmp_path): + store = MagicMock(spec=NativeStore) + store.url = "https://store" + store.root = None + entry = NativeEntry(sha256="1" * 64, size=NETCDF_FETCH_BYTES + 1) + report = _report([_file_change("out.nc", None, entry)]) + + file = analyse(report, store, fetch=True, workdir=tmp_path).cases[0].files[0] + + assert "too large to analyse" in file.netcdf.note + store.fetch.assert_not_called() + + def test_fetching_disabled_leaves_a_note(self, tmp_path): + store = MagicMock(spec=NativeStore) + store.url = "https://store" + store.root = None + report = _report([_file_change("out.nc", None, NativeEntry(sha256="1" * 64, size=10))]) + + file = analyse(report, store, fetch=False, workdir=tmp_path).cases[0].files[0] + + assert file.netcdf.note == "fetching disabled" diff --git a/packages/climate-ref/tests/unit/baseline_report/test_collect.py b/packages/climate-ref/tests/unit/baseline_report/test_collect.py new file mode 100644 index 000000000..a2b1c84cd --- /dev/null +++ b/packages/climate-ref/tests/unit/baseline_report/test_collect.py @@ -0,0 +1,169 @@ +"""Tests for collecting the manifest changes on a branch.""" + +import pytest +from git import Repo + +from climate_ref.baseline_report.collect import ( + FileKind, + case_label, + classify, + collect, +) +from climate_ref_core.regression.manifest import SCHEMA_VERSION, Manifest, NativeEntry + +MANIFEST_PATH = "packages/climate-ref-example/tests/test-data/global-mean-timeseries/default/manifest.json" + + +def _digest(char: str) -> str: + """Build a valid sha256 digest from a single repeated hex character.""" + return char * 64 + + +def _write_manifest(repo_dir, rel_path, *, version, native, committed=None, catalog_hash=None): + """Write a manifest at ``rel_path`` inside ``repo_dir``.""" + path = repo_dir / rel_path + path.parent.mkdir(parents=True, exist_ok=True) + Manifest( + schema=SCHEMA_VERSION, + test_case_version=version, + diagnostic_version=1, + committed=committed or {}, + native=native, + catalog_hash=catalog_hash, + ).dump(path) + return path + + +@pytest.fixture +def repo(tmp_path): + """A git repository with one manifest committed twice, the second time with changes.""" + repo = Repo.init(tmp_path) + with repo.config_writer() as writer: + writer.set_value("user", "name", "test") + writer.set_value("user", "email", "test@example.com") + + _write_manifest( + tmp_path, + MANIFEST_PATH, + version=3, + native={ + "kept.png": NativeEntry(sha256=_digest("1"), size=10), + "changed.json": NativeEntry(sha256=_digest("2"), size=20), + "removed.nc": NativeEntry(sha256=_digest("3"), size=30), + }, + committed={"series.json": _digest("a")}, + ) + repo.git.add("-A") + repo.index.commit("base") + + _write_manifest( + tmp_path, + MANIFEST_PATH, + version=4, + native={ + "kept.png": NativeEntry(sha256=_digest("1"), size=10), + "changed.json": NativeEntry(sha256=_digest("4"), size=25), + "added.bin": NativeEntry(sha256=_digest("5"), size=40), + }, + committed={"series.json": _digest("b")}, + ) + repo.git.add("-A") + repo.index.commit("head") + return repo + + +class TestClassify: + @pytest.mark.parametrize( + "name, expected", + [ + ("plot.png", FileKind.IMAGE), + ("plot.JPG", FileKind.IMAGE), + ("plot.jpeg", FileKind.IMAGE), + ("plot.gif", FileKind.IMAGE), + ("plot.svg", FileKind.IMAGE), + ("a.json", FileKind.TEXT), + ("a.csv", FileKind.TEXT), + ("a.yml", FileKind.TEXT), + ("a.yaml", FileKind.TEXT), + ("a.html", FileKind.TEXT), + ("a.txt", FileKind.TEXT), + ("a.md", FileKind.TEXT), + ("a.log", FileKind.TEXT), + ("out.nc", FileKind.NETCDF), + ("blob.bin", FileKind.OTHER), + ("noextension", FileKind.OTHER), + ], + ) + def test_suffixes(self, name, expected): + assert classify(name) is expected + + +class TestCaseLabel: + def test_strips_the_provider_prefix(self): + assert case_label(MANIFEST_PATH) == "example/global-mean-timeseries/default" + + def test_short_path_keeps_only_the_provider(self): + assert case_label("packages/climate-ref-pmp") == "pmp" + + +class TestCollect: + def test_pairs_native_entries(self, repo): + report = collect(repo, "HEAD~1") + + assert report.base_ref == "HEAD~1" + assert report.head_sha == repo.head.commit.hexsha + assert len(report.cases) == 1 + + case = report.cases[0] + assert case.label == "example/global-mean-timeseries/default" + assert not case.is_new + assert not case.is_removed + + # Unchanged entries are dropped, and the rest are in name order. + assert [(f.name, f.status, f.kind) for f in case.files] == [ + ("added.bin", "added", FileKind.OTHER), + ("changed.json", "changed", FileKind.TEXT), + ("removed.nc", "removed", FileKind.NETCDF), + ] + + def test_reports_metadata_and_committed_changes(self, repo): + case = collect(repo, "HEAD~1").cases[0] + + assert case.metadata == ("test_case_version: 3 -> 4",) + assert case.committed == ("series.json",) + + def test_new_case_has_no_base(self, tmp_path): + repo = Repo.init(tmp_path) + with repo.config_writer() as writer: + writer.set_value("user", "name", "test") + writer.set_value("user", "email", "test@example.com") + (tmp_path / "README.md").write_text("seed") + repo.git.add("-A") + repo.index.commit("seed") + + _write_manifest( + tmp_path, + MANIFEST_PATH, + version=7, + native={"plot.png": NativeEntry(sha256=_digest("1"), size=10)}, + ) + repo.git.add("-A") + repo.index.commit("add case") + + case = collect(repo, "HEAD~1").cases[0] + + assert case.base is None + assert case.is_new + assert case.metadata == ("new test case at test_case_version 7",) + assert [f.status for f in case.files] == ["added"] + + def test_no_changes_gives_no_cases(self, repo): + assert collect(repo, "HEAD").cases == () + + def test_an_unreadable_manifest_is_skipped(self, repo, tmp_path): + # A manifest written by an incompatible version should cost its own case, not the report. + (tmp_path / MANIFEST_PATH).write_text('{"schema": 1}') + repo.git.add("-A") + repo.index.commit("break the manifest") + + assert collect(repo, "HEAD~1").cases == () diff --git a/packages/climate-ref/tests/unit/baseline_report/test_render.py b/packages/climate-ref/tests/unit/baseline_report/test_render.py new file mode 100644 index 000000000..2f34a49a9 --- /dev/null +++ b/packages/climate-ref/tests/unit/baseline_report/test_render.py @@ -0,0 +1,627 @@ +"""Tests for the static HTML the report is written as.""" + +from html.parser import HTMLParser +from unittest.mock import MagicMock + +import pytest +from attrs import evolve + +from climate_ref.baseline_report.analyse import ( + AnalysedReport, + DiffLine, + NetcdfDiff, + Pair, + StatRow, + TextDiff, + analyse, +) +from climate_ref.baseline_report.collect import CaseChange, FileChange, FileKind, Report, classify +from climate_ref.baseline_report.render import render_case, render_comment, render_index, write_site +from climate_ref_core.regression.manifest import SCHEMA_VERSION, Manifest, NativeEntry +from climate_ref_core.regression.store import NativeStore + +STORE_URL = "https://store.example" + + +class Collector(HTMLParser): + """Collect the tags and attributes of a rendered page.""" + + def __init__(self): + super().__init__() + self.tags: list[tuple[str, dict[str, str]]] = [] + + def handle_starttag(self, tag, attrs): + self.tags.append((tag, dict(attrs))) + + +def _parse(html: str) -> Collector: + """Parse a page and return its collected tags.""" + collector = Collector() + collector.feed(html) + return collector + + +def _tags(html: str, name: str) -> list[dict[str, str]]: + """Return the attributes of every ``name`` tag in a page.""" + return [attrs for tag, attrs in _parse(html).tags if tag == name] + + +def _hrefs(html: str) -> list[str]: + """Return every href in a page.""" + return [attrs["href"] for _, attrs in _parse(html).tags if "href" in attrs] + + +def _manifest(version: int) -> Manifest: + """Build a manifest carrying only the fields the templates read.""" + return Manifest( + schema=SCHEMA_VERSION, + test_case_version=version, + diagnostic_version=1, + committed={}, + native={}, + ) + + +def _entry(char: str, size: int = 10) -> NativeEntry: + """Build a manifest entry from a single repeated hex character.""" + return NativeEntry(sha256=char * 64, size=size) + + +def _change(name: str, old: NativeEntry | None, new: NativeEntry | None) -> FileChange: + """Build one file change with the kind its name implies.""" + return FileChange(name=name, old=old, new=new, kind=classify(name)) + + +def _case_change(changes, label="example/diag/case", base=None, head=None) -> CaseChange: + """Build one collected case.""" + return CaseChange( + label=label, + rel_path=f"packages/climate-ref-{label.split('/')[0]}/tests/test-data/manifest.json", + base=base, + head=head, + files=tuple(changes), + committed=("series.json",), + metadata=("test_case_version: 3 -> 4",), + ) + + +def _analysed(cases, tmp_path, diffs=None) -> AnalysedReport: + """ + Analyse collected cases with a store that is never read. + + Running the real :func:`analyse` keeps these tests pinned to the counts, partitions and + back links the pages are actually built from. ``diffs`` replaces the placeholder note on a + named file, which is how a specific diff shape is put in front of the templates. + """ + store = MagicMock(spec=NativeStore) + store.url = STORE_URL + store.root = None + report = analyse( + Report(base_ref="origin/main", head_sha="a" * 40, cases=tuple(cases)), + store, + fetch=False, + workdir=tmp_path, + ) + if not diffs: + return report + + def _replace(file): + """Swap in the fixture diff for a named file, leaving the rest as analysed.""" + found = diffs.get(file.change.name) + if found is None: + return file + if isinstance(found, NetcdfDiff): + return evolve(file, netcdf=found) + return evolve(file, text=found) + + return evolve( + report, + cases=tuple( + evolve( + case, + files=tuple(_replace(file) for file in case.files), + texts=tuple(_replace(file) for file in case.texts), + netcdfs=tuple(_replace(file) for file in case.netcdfs), + ) + for case in report.cases + ), + ) + + +@pytest.fixture +def changed_image_case(tmp_path): + """A report whose single case has one changed image.""" + return _analysed( + [ + _case_change( + [_change("plot.png", _entry("1"), _entry("2", 20))], base=_manifest(3), head=_manifest(4) + ) + ], + tmp_path, + ) + + +class TestIndex: + def test_one_row_per_case(self, tmp_path): + report = _analysed( + [ + _case_change([], label="example/diag/a", base=_manifest(1), head=_manifest(2)), + _case_change([], label="pmp/diag/b", base=_manifest(1), head=_manifest(2)), + ], + tmp_path, + ) + + html = render_index(report) + + assert html.count("") == 3 # one header row plus one per case + assert "example/diag/a" in html + assert "pmp/diag/b" in html + + def test_every_link_ends_in_index_html(self, tmp_path): + report = _analysed([_case_change([], base=_manifest(1), head=_manifest(2))], tmp_path) + + assert _hrefs(render_index(report)) == ["example/diag/case/index.html"] + + def test_versions_column(self, tmp_path): + report = _analysed([_case_change([], base=_manifest(3), head=_manifest(4))], tmp_path) + + assert "v3 -> v4" in render_index(report) + + def test_a_column_header_per_kind(self, tmp_path): + report = _analysed([_case_change([], base=_manifest(1), head=_manifest(2))], tmp_path) + + headers = render_index(report) + + for kind in FileKind: + assert f"{kind.value}" in headers + + def test_counts_appear_per_kind(self, tmp_path): + report = _analysed( + [ + _case_change( + [_change("a.png", None, _entry("1")), _change("b.nc", _entry("2"), None)], + base=_manifest(1), + head=_manifest(2), + ) + ], + tmp_path, + ) + + html = render_index(report) + + assert '+1' in html + assert '-1' in html + + def test_an_empty_report_says_so(self, tmp_path): + html = render_index(_analysed([], tmp_path)) + + assert "No baseline manifests changed" in html + assert "" not in html + + +class TestCasePage: + def test_a_changed_image_renders_two_images(self, changed_image_case): + images = _tags(render_case(changed_image_case, changed_image_case.cases[0]), "img") + + assert len(images) == 2 + assert all(image["src"].startswith(STORE_URL) for image in images) + + def test_an_added_image_renders_one_image_and_a_placeholder(self, tmp_path): + report = _analysed([_case_change([_change("plot.png", None, _entry("2"))])], tmp_path) + + html = render_case(report, report.cases[0]) + + assert len(_tags(html, "img")) == 1 + assert 'class="absent"' in html + + def test_a_text_diff_renders_one_span_per_line(self, tmp_path): + diff = TextDiff( + lines=( + DiffLine(kind="header", text="--- old"), + DiffLine(kind="hunk", text="@@ -1 +1 @@"), + DiffLine(kind="remove", text="-a"), + DiffLine(kind="add", text="+b"), + ), + note=None, + elided=0, + ) + report = _analysed( + [_case_change([_change("series.csv", _entry("1"), _entry("2"))])], + tmp_path, + diffs={"series.csv": diff}, + ) + + html = render_case(report, report.cases[0]) + spans = [ + attrs["class"] + for attrs in _tags(html, "span") + if attrs.get("class") in {"header", "hunk", "remove", "add"} + ] + + assert spans == ["header", "hunk", "remove", "add"] + + def test_a_note_replaces_the_diff(self, tmp_path): + report = _analysed([_case_change([_change("series.csv", None, _entry("2"))])], tmp_path) + + html = render_case(report, report.cases[0]) + + assert "fetching disabled" in html + assert '
' not in html
+
+    def test_elided_lines_are_reported(self, tmp_path):
+        diff = TextDiff(lines=(DiffLine(kind="add", text="+a"),), note=None, elided=7)
+        report = _analysed(
+            [_case_change([_change("series.csv", None, _entry("2"))])],
+            tmp_path,
+            diffs={"series.csv": diff},
+        )
+
+        assert "7 further diff line(s) elided" in render_case(report, report.cases[0])
+
+    def test_netcdf_renders_as_a_row(self, tmp_path):
+        report = _analysed([_case_change([_change("out.nc", _entry("1"), None)])], tmp_path)
+
+        html = render_case(report, report.cases[0])
+
+        assert "out.nc" in html
+        assert "was 10 B" in html
+        assert not _tags(html, "img")
+
+    def test_the_back_link_matches_the_label_depth(self, tmp_path):
+        report = _analysed([_case_change([], label="pmp/diag/one")], tmp_path)
+
+        assert "../../../index.html" in _hrefs(render_case(report, report.cases[0]))
+
+    def test_a_shallow_label_gets_a_shallow_back_link(self, tmp_path):
+        report = _analysed([_case_change([], label="pmp")], tmp_path)
+
+        assert "../index.html" in _hrefs(render_case(report, report.cases[0]))
+
+    def test_a_changed_file_shows_its_signed_size_delta(self, changed_image_case):
+        assert "(+10)" in render_case(changed_image_case, changed_image_case.cases[0])
+
+    def test_a_text_diff_names_both_digests(self, tmp_path):
+        diff = TextDiff(lines=(DiffLine(kind="add", text="+a"),), note=None, elided=0)
+        report = _analysed(
+            [_case_change([_change("series.csv", _entry("1"), _entry("2"))])],
+            tmp_path,
+            diffs={"series.csv": diff},
+        )
+
+        html = render_case(report, report.cases[0])
+
+        assert "1" * 12 in html
+        assert "2" * 12 in html
+
+    def test_links_are_internal_index_pages_or_store_blobs(self, changed_image_case):
+        for href in _hrefs(render_case(changed_image_case, changed_image_case.cases[0])):
+            assert href.endswith("index.html") or href.startswith(STORE_URL)
+
+    def test_metadata_and_committed_are_listed(self, changed_image_case):
+        html = render_case(changed_image_case, changed_image_case.cases[0])
+
+        assert "test_case_version: 3 -> 4" in html
+        assert "series.json" in html
+
+
+class TestWriteSite:
+    def test_writes_an_index_and_a_page_per_case(self, tmp_path, changed_image_case):
+        index = write_site(changed_image_case, tmp_path / "out")
+
+        assert index == tmp_path / "out" / "index.html"
+        assert index.exists()
+        assert (tmp_path / "out" / "example" / "diag" / "case" / "index.html").exists()
+
+    def test_an_empty_report_still_writes_an_index(self, tmp_path):
+        index = write_site(_analysed([], tmp_path), tmp_path / "out")
+
+        assert index.exists()
+
+
+def _stat_row(name, *, moved, **overrides):
+    """Build a stats row with every field set, so a template cannot pass on a missing one."""
+    fields = dict(
+        shape=Pair("2x2", "2x2"),
+        minimum=Pair(1.0, 1.0),
+        maximum=Pair(4.0, 4.0),
+        mean=Pair(2.5, 2.5),
+        nan=Pair(0, 0),
+        max_abs_diff=0.0,
+        max_rel_diff=0.0,
+        cells_differ=0,
+    )
+    fields.update(overrides)
+    return StatRow(name=name, moved=moved, **fields)
+
+
+def _netcdf_diff(
+    rows, header=(), header_old=("xarray.Dataset {",), header_new=("xarray.Dataset {",), note=None
+):
+    """Build a NetCDF analysis with the header fields filled in."""
+    return NetcdfDiff(header=header, header_old=header_old, header_new=header_new, rows=rows, note=note)
+
+
+def _netcdf_case(tmp_path, diff, name="out.nc"):
+    """A report whose single case has one changed NetCDF file carrying ``diff``."""
+    return _analysed(
+        [_case_change([_change(name, _entry("1"), _entry("2", 20))], base=_manifest(3), head=_manifest(4))],
+        tmp_path,
+        diffs={name: diff},
+    )
+
+
+class TestNetcdfBlock:
+    def test_only_the_moved_row_is_shaded(self, tmp_path):
+        diff = _netcdf_diff(
+            header=(DiffLine(kind="add", text="+ title: b"),),
+            rows=(
+                _stat_row("tas", moved=True, max_abs_diff=0.5, max_rel_diff=0.125, cells_differ=1),
+                _stat_row("pr", moved=False),
+            ),
+        )
+        report = _netcdf_case(tmp_path, diff)
+
+        html = render_case(report, report.cases[0])
+
+        assert html.count('') == 1
+        assert [attrs.get("class") for attrs in _tags(html, "table")] == ["stats"]
+        assert "0.5" in html
+        assert "0.125" in html
+
+    def test_only_the_values_that_moved_are_emphasised(self, tmp_path):
+        diff = _netcdf_diff(
+            rows=(
+                _stat_row(
+                    "tas",
+                    moved=True,
+                    maximum=Pair(4.0, 4.5),
+                    max_abs_diff=0.5,
+                    max_rel_diff=0.125,
+                    cells_differ=1,
+                ),
+            ),
+        )
+        report = _netcdf_case(tmp_path, diff)
+
+        html = render_case(report, report.cases[0])
+
+        assert "4 -> 4.5" in html  # the max moved
+        assert "1 -> 1" in html  # the min did not, so it stays plain
+        assert "0.5" in html  # and so do the three diff columns
+        assert html.count("") == 4
+
+    def test_an_unchanged_row_emphasises_nothing(self, tmp_path):
+        report = _netcdf_case(tmp_path, _netcdf_diff(rows=(_stat_row("tas", moved=False),)))
+
+        html = render_case(report, report.cases[0])
+
+        assert "" not in html
+
+    def test_a_note_replaces_the_table(self, tmp_path):
+        report = _netcdf_case(tmp_path, _netcdf_diff(rows=(), note="could not open: boom"))
+
+        html = render_case(report, report.cases[0])
+
+        assert "could not open: boom" in html
+        assert " 2x2" in html
+        assert "-" in html
+
+    def test_the_page_carries_no_dash_that_is_not_ascii(self, tmp_path):
+        diff = _netcdf_diff(rows=(_stat_row("tas", moved=False),))
+        report = _netcdf_case(tmp_path, diff)
+
+        html = render_case(report, report.cases[0])
+
+        assert "\u2013" not in html
+        assert "\u2014" not in html
+
+    def test_a_wide_table_is_wrapped_so_it_can_scroll(self, tmp_path):
+        diff = _netcdf_diff(rows=(_stat_row("tas", moved=False),))
+        report = _netcdf_case(tmp_path, diff, name="a" * 120 + ".nc")
+
+        html = render_case(report, report.cases[0])
+
+        assert '
' in html + assert "a" * 120 in html + + def test_matching_headers_are_marked_unchanged_but_still_shown(self, tmp_path): + diff = _netcdf_diff( + header=(DiffLine(kind="context", text=" xarray.Dataset {"),), + rows=(_stat_row("tas", moved=False),), + ) + report = _netcdf_case(tmp_path, diff) + + html = render_case(report, report.cases[0]) + + assert "(unchanged)" in html + assert "xarray.Dataset {" in html + + def test_both_headers_are_available_side_by_side(self, tmp_path): + diff = _netcdf_diff( + header=(DiffLine(kind="remove", text="- lat = 90 ;"),), + header_old=("dimensions:", " lat = 90 ;"), + header_new=("dimensions:", " lat = 45 ;"), + rows=(_stat_row("tas", moved=True, cells_differ=1),), + ) + report = _netcdf_case(tmp_path, diff) + + html = render_case(report, report.cases[0]) + + assert 'data-header-view="split"' in html + assert "lat = 90 ;" in html + assert "lat = 45 ;" in html + assert html.count('data-view="diff"') == 1 + + def test_an_absent_side_says_so_in_the_split_view(self, tmp_path): + diff = _netcdf_diff( + header=(DiffLine(kind="add", text="+ dimensions:"),), + header_old=(), + header_new=("dimensions:",), + rows=(_stat_row("tas", moved=True, shape=Pair(None, "2x2")),), + ) + report = _netcdf_case(tmp_path, diff) + + html = render_case(report, report.cases[0]) + + assert '
absent
' in html + + +BASE_URL = "https://reports.example/912/0c7e1d4abc12" + +MARKER = "" + + +def _rows(markdown: str) -> list[str]: + """Return the table's body rows.""" + return [line for line in markdown.splitlines() if line.startswith("| `")] + + +class TestComment: + def test_one_row_per_case(self, tmp_path): + report = _analysed( + [ + _case_change([], label="example/diag/a", base=_manifest(1), head=_manifest(2)), + _case_change([], label="pmp/diag/b", base=_manifest(1), head=_manifest(2)), + ], + tmp_path, + ) + + markdown = render_comment(report, BASE_URL) + + assert len(_rows(markdown)) == 2 + assert "`example/diag/a`" in markdown + assert "`pmp/diag/b`" in markdown + + def test_every_row_links_into_the_hosted_report(self, changed_image_case): + markdown = render_comment(changed_image_case, BASE_URL) + + assert f"[view]({BASE_URL}/example/diag/case/index.html)" in markdown + assert f"[Full report]({BASE_URL}/index.html)" in markdown + + def test_a_trailing_slash_on_the_base_url_is_ignored(self, changed_image_case): + markdown = render_comment(changed_image_case, BASE_URL + "/") + + assert "//index.html" not in markdown + + def test_rows_stay_small(self, changed_image_case): + markdown = render_comment(changed_image_case, BASE_URL) + + assert all(len(row.encode("utf-8")) <= 300 for row in _rows(markdown)) + + def test_counts_use_the_short_form(self, tmp_path): + report = _analysed( + [ + _case_change( + [ + _change("added.png", None, _entry("1")), + _change("moved.png", _entry("2"), _entry("3")), + _change("gone.txt", _entry("4"), None), + ], + base=_manifest(3), + head=_manifest(4), + ) + ], + tmp_path, + ) + + row = _rows(render_comment(report, BASE_URL))[0] + + assert "| v3 -> v4 |" in row + assert "| +1 ~1 |" in row + assert "| -1 |" in row + assert "| none |" in row + + @pytest.mark.parametrize( + "base, head, expected", + [(_manifest(3), None, "removed"), (None, _manifest(4), "new")], + ) + def test_a_one_sided_case_says_so(self, tmp_path, base, head, expected): + report = _analysed([_case_change([], base=base, head=head)], tmp_path) + + assert f"| {expected} |" in _rows(render_comment(report, BASE_URL))[0] + + def test_the_header_carries_a_column_per_kind(self, changed_image_case): + markdown = render_comment(changed_image_case, BASE_URL) + + header = next(line for line in markdown.splitlines() if line.startswith("| case |")) + assert header.count("|") == len(changed_image_case.kinds) + 4 + for kind in changed_image_case.kinds: + assert f"| {kind} |" in header + + def test_every_row_has_the_same_column_count_as_the_header(self, changed_image_case): + markdown = render_comment(changed_image_case, BASE_URL) + + header = next(line for line in markdown.splitlines() if line.startswith("| case |")) + assert all(row.count("|") == header.count("|") for row in _rows(markdown)) + + def test_each_count_sits_under_its_own_kind(self, tmp_path): + report = _analysed( + [ + _case_change( + [_change("added.png", None, _entry("1")), _change("gone.txt", _entry("4"), None)], + base=_manifest(3), + head=_manifest(4), + ) + ], + tmp_path, + ) + markdown = render_comment(report, BASE_URL) + + header = [ + c.strip() + for c in next(line for line in markdown.splitlines() if line.startswith("| case |")).split("|") + ] + cells = [c.strip() for c in _rows(markdown)[0].split("|")] + assert cells[header.index("image")] == "+1" + assert cells[header.index("text")] == "-1" + assert cells[header.index("netcdf")] == "none" + + def test_zero_cases_renders_the_no_change_message(self, tmp_path): + markdown = render_comment(_analysed([], tmp_path), BASE_URL) + + assert "No baseline manifests changed against `origin/main`." in markdown + assert "| case |" not in markdown + assert MARKER in markdown + + def test_the_marker_appears_once(self, changed_image_case): + assert render_comment(changed_image_case, BASE_URL).count(MARKER) == 1 + + def test_previous_reports_are_listed(self, changed_image_case): + markdown = render_comment( + changed_image_case, + BASE_URL, + previous=[("abc1234", "https://reports.example/912/abc1234/index.html")], + ) + + assert "[abc1234](https://reports.example/912/abc1234/index.html)" in markdown + + def test_no_previous_reports_leaves_the_line_out(self, changed_image_case): + assert "Previous reports" not in render_comment(changed_image_case, BASE_URL) + + def test_labels_are_not_html_escaped(self, tmp_path): + report = _analysed([_case_change([], base=_manifest(3), head=_manifest(4))], tmp_path) + + assert "->" not in render_comment(report, BASE_URL) diff --git a/packages/climate-ref/tests/unit/baseline_report/test_upload.py b/packages/climate-ref/tests/unit/baseline_report/test_upload.py new file mode 100644 index 000000000..f3b972820 --- /dev/null +++ b/packages/climate-ref/tests/unit/baseline_report/test_upload.py @@ -0,0 +1,86 @@ +"""Tests for pushing a rendered report into the report store.""" + +from pathlib import Path + +import pytest +from attrs import define, field + +from climate_ref.baseline_report.upload import DEFAULT_CONTENT_TYPE, content_type_for, upload_site + +PREFIX = "912/0c7e1d4abc12" + + +@define +class RecordingStore: + """A report store that records what was put rather than storing it.""" + + url: str = "https://reports.example" + puts: list[tuple[str, Path, str]] = field(factory=list) + + def put(self, key: str, path: Path, content_type: str) -> str: + self.puts.append((key, path, content_type)) + return self.url_for(key) + + def url_for(self, key: str) -> str: + return f"{self.url}/{key}" + + +@pytest.fixture +def site(tmp_path: Path) -> Path: + """A three-file site with one page nested a directory deep.""" + out = tmp_path / "site" + (out / "example" / "diag").mkdir(parents=True) + (out / "index.html").write_text("

index

", encoding="utf-8") + (out / "report.css").write_text("body {}", encoding="utf-8") + (out / "example" / "diag" / "index.html").write_text("

case

", encoding="utf-8") + return out + + +@pytest.mark.parametrize( + "name, expected", + [ + ("index.html", "text/html; charset=utf-8"), + ("report.CSS", "text/css; charset=utf-8"), + ("report.js", "text/javascript; charset=utf-8"), + ("plot.png", "image/png"), + ("plot.svg", "image/svg+xml"), + ("blob.bin", DEFAULT_CONTENT_TYPE), + ("no-extension", DEFAULT_CONTENT_TYPE), + ], +) +def test_content_type_for(name, expected): + assert content_type_for(Path(name)) == expected + + +class TestUploadSite: + def test_every_file_lands_under_the_prefix(self, site): + store = RecordingStore() + + upload_site(site, store, PREFIX) + + assert sorted(key for key, _, _ in store.puts) == [ + f"{PREFIX}/example/diag/index.html", + f"{PREFIX}/index.html", + f"{PREFIX}/report.css", + ] + + def test_content_types_are_set(self, site): + store = RecordingStore() + + upload_site(site, store, PREFIX) + + by_key = {key: content_type for key, _, content_type in store.puts} + assert by_key[f"{PREFIX}/index.html"] == "text/html; charset=utf-8" + assert by_key[f"{PREFIX}/report.css"] == "text/css; charset=utf-8" + + def test_returns_the_index_url(self, site): + store = RecordingStore() + + assert upload_site(site, store, PREFIX) == f"https://reports.example/{PREFIX}/index.html" + + def test_directories_are_not_uploaded(self, site): + store = RecordingStore() + + upload_site(site, store, PREFIX) + + assert all(path.is_file() for _, path, _ in store.puts) diff --git a/packages/climate-ref/tests/unit/cli/test_test_cases.py b/packages/climate-ref/tests/unit/cli/test_test_cases.py index 897a16e71..7166cf1c0 100644 --- a/packages/climate-ref/tests/unit/cli/test_test_cases.py +++ b/packages/climate-ref/tests/unit/cli/test_test_cases.py @@ -2868,3 +2868,184 @@ def test_diagnostic_version_decrease_fails(self, invoke_cli, mocker, tmp_path): result = invoke_cli(["test-cases", "ci-gate"], expected_exit_code=1) assert result.exit_code == 1 assert "fail" in result.output + + +class TestDiff: + """``ref test-cases diff`` writes a local HTML report.""" + + def test_no_changes_still_writes_an_index(self, invoke_cli, mocker, tmp_path): + repo = MagicMock() + repo.working_tree_dir = str(tmp_path) + repo.git.diff.return_value = "" + repo.head.commit.hexsha = "a" * 40 + mocker.patch("climate_ref.cli.test_cases.diff.get_repo_for_path", return_value=repo) + + out = tmp_path / "out" + invoke_cli(["test-cases", "diff", "--html-dir", str(out), "--no-fetch"]) + + assert (out / "index.html").exists() + assert "No baseline manifests changed" in (out / "index.html").read_text() + + def test_outside_a_repository_exits_one(self, invoke_cli, mocker, tmp_path): + mocker.patch("climate_ref.cli.test_cases.diff.get_repo_for_path", return_value=None) + + invoke_cli( + ["test-cases", "diff", "--html-dir", str(tmp_path / "out"), "--no-fetch"], + expected_exit_code=1, + ) + + def test_a_changed_case_gets_a_page(self, invoke_cli, mocker, tmp_path): + from climate_ref_core.regression.manifest import SCHEMA_VERSION, Manifest, NativeEntry + + rel_path = "packages/climate-ref-example/tests/test-data/diag/case/manifest.json" + manifest_path = tmp_path / rel_path + manifest_path.parent.mkdir(parents=True) + Manifest( + schema=SCHEMA_VERSION, + test_case_version=4, + diagnostic_version=1, + committed={}, + native={"plot.png": NativeEntry(sha256="b" * 64, size=20)}, + ).dump(manifest_path) + + repo = MagicMock() + repo.working_tree_dir = str(tmp_path) + repo.git.diff.return_value = rel_path + repo.git.show.return_value = json.dumps( + { + "schema": SCHEMA_VERSION, + "test_case_version": 3, + "diagnostic_version": 1, + "committed": {}, + "native": {"plot.png": {"sha256": "a" * 64, "size": 10}}, + } + ) + repo.head.commit.hexsha = "c" * 40 + mocker.patch("climate_ref.cli.test_cases.diff.get_repo_for_path", return_value=repo) + + out = tmp_path / "out" + invoke_cli(["test-cases", "diff", "--html-dir", str(out), "--no-fetch"]) + + page = out / "example" / "diag" / "case" / "index.html" + assert page.exists() + assert page.read_text().count("") == 1 + + def test_an_unsafe_upload_prefix_exits_one(self, invoke_cli, mocker, tmp_path, monkeypatch): + monkeypatch.setenv("REF_REPORT_STORE_URL", str(tmp_path / "reports")) + + repo = MagicMock() + repo.working_tree_dir = str(tmp_path) + repo.git.diff.return_value = "" + repo.head.commit.hexsha = "a" * 40 + mocker.patch("climate_ref.cli.test_cases.diff.get_repo_for_path", return_value=repo) + + invoke_cli( + [ + "test-cases", + "diff", + "--html-dir", + str(tmp_path / "out"), + "--no-fetch", + "--upload", + "../escape", + ], + expected_exit_code=1, + ) + + def test_an_unusable_report_store_exits_one(self, invoke_cli, mocker, tmp_path, monkeypatch): + blocker = tmp_path / "blocker" + blocker.write_text("not a directory") + monkeypatch.setenv("REF_REPORT_STORE_URL", str(blocker / "reports")) + + repo = MagicMock() + repo.working_tree_dir = str(tmp_path) + repo.git.diff.return_value = "" + repo.head.commit.hexsha = "a" * 40 + mocker.patch("climate_ref.cli.test_cases.diff.get_repo_for_path", return_value=repo) + + invoke_cli( + [ + "test-cases", + "diff", + "--html-dir", + str(tmp_path / "out"), + "--no-fetch", + "--upload", + "912/abc", + ], + expected_exit_code=1, + ) + + def test_the_comment_links_locally_without_upload(self, invoke_cli, mocker, tmp_path): + from climate_ref_core.regression.manifest import SCHEMA_VERSION, Manifest + + rel_path = "packages/climate-ref-example/tests/test-data/diag/case/manifest.json" + manifest_path = tmp_path / rel_path + manifest_path.parent.mkdir(parents=True) + Manifest( + schema=SCHEMA_VERSION, + test_case_version=4, + diagnostic_version=1, + committed={}, + native={}, + ).dump(manifest_path) + + repo = MagicMock() + repo.working_tree_dir = str(tmp_path) + repo.git.diff.return_value = rel_path + repo.git.show.return_value = json.dumps( + { + "schema": SCHEMA_VERSION, + "test_case_version": 3, + "diagnostic_version": 1, + "committed": {}, + "native": {}, + } + ) + repo.head.commit.hexsha = "c" * 40 + mocker.patch("climate_ref.cli.test_cases.diff.get_repo_for_path", return_value=repo) + + out = tmp_path / "out" + comment = tmp_path / "comment.md" + invoke_cli( + [ + "test-cases", + "diff", + "--html-dir", + str(out), + "--no-fetch", + "--comment-output", + str(comment), + ] + ) + + assert f"{out.resolve().as_uri()}/index.html" in comment.read_text() diff --git a/packages/climate-ref/tests/unit/datasets/test_catalog_builder.py b/packages/climate-ref/tests/unit/datasets/test_catalog_builder.py index b5e3191ce..d205ae72d 100644 --- a/packages/climate-ref/tests/unit/datasets/test_catalog_builder.py +++ b/packages/climate-ref/tests/unit/datasets/test_catalog_builder.py @@ -60,7 +60,7 @@ def empty_dir(tmp_path): class TestDiscoverFiles: def test_finds_nc_files(self, tmp_tree): - files = discover_files([str(tmp_tree)], include_patterns=["*.nc"], depth=10) + files = discover_files([str(tmp_tree)], include_patterns=["*.nc"]) names = [Path(f).name for f in files] assert "root.nc" in names assert "a.nc" in names @@ -69,41 +69,34 @@ def test_finds_nc_files(self, tmp_tree): # .txt should be excluded assert "root.txt" not in names - def test_depth_limiting(self, tmp_tree): - # depth=0: only root directory - files_d0 = discover_files([str(tmp_tree)], include_patterns=["*.nc"], depth=0) - names_d0 = [Path(f).name for f in files_d0] - assert names_d0 == ["root.nc"] + def test_walks_arbitrarily_deep_trees(self, tmp_path): + leaf = tmp_path + for level in range(14): + leaf = leaf / f"level{level}" + leaf.mkdir(parents=True) + (leaf / "deep.nc").touch() - # depth=1: root + sub - files_d1 = discover_files([str(tmp_tree)], include_patterns=["*.nc"], depth=1) - names_d1 = sorted(Path(f).name for f in files_d1) - assert names_d1 == ["a.nc", "root.nc"] - - # depth=2: root + sub + deep - files_d2 = discover_files([str(tmp_tree)], include_patterns=["*.nc"], depth=2) - names_d2 = sorted(Path(f).name for f in files_d2) - assert names_d2 == ["a.nc", "b.nc", "root.nc"] + assert discover_files([str(tmp_path)], include_patterns=["*.nc"]) == [str(leaf / "deep.nc")] def test_nonexistent_path(self): - files = discover_files(["/nonexistent/path"], include_patterns=["*.nc"], depth=5) + files = discover_files(["/nonexistent/path"], include_patterns=["*.nc"]) assert files == [] def test_single_file_path(self, tmp_tree): nc_file = str(tmp_tree / "root.nc") - files = discover_files([nc_file], include_patterns=["*.nc"], depth=0) + files = discover_files([nc_file], include_patterns=["*.nc"]) assert files == [nc_file] # Non-matching pattern - files = discover_files([nc_file], include_patterns=["*.txt"], depth=0) + files = discover_files([nc_file], include_patterns=["*.txt"]) assert files == [] def test_empty_directory(self, empty_dir): - files = discover_files([str(empty_dir)], include_patterns=["*.nc"], depth=5) + files = discover_files([str(empty_dir)], include_patterns=["*.nc"]) assert files == [] def test_default_include_all(self, tmp_tree): - files = discover_files([str(tmp_tree)], depth=0) + files = discover_files([str(tmp_tree)]) names = sorted(Path(f).name for f in files) assert "root.nc" in names assert "root.txt" in names @@ -145,7 +138,6 @@ def test_sequential(self, tmp_tree): paths=[str(tmp_tree)], parsing_func=_good_parser, include_patterns=["*.nc"], - depth=10, n_jobs=1, ) assert isinstance(df, pd.DataFrame) @@ -158,7 +150,6 @@ def test_parallel(self, tmp_tree): paths=[str(tmp_tree)], parsing_func=_good_parser, include_patterns=["*.nc"], - depth=10, n_jobs=2, ) assert len(df) == 4 @@ -168,7 +159,6 @@ def test_parallel_all_cpus(self, tmp_tree): paths=[str(tmp_tree)], parsing_func=_good_parser, include_patterns=["*.nc"], - depth=10, n_jobs=-1, ) assert len(df) == 4 @@ -180,11 +170,10 @@ def test_invalid_asset_filtering(self, tmp_tree): paths=[str(tmp_tree)], parsing_func=_mixed_parser, include_patterns=["*.nc", "*.txt"], - depth=0, n_jobs=1, ) - # Only root.nc should survive (depth=0, .txt filtered as INVALID) - assert len(df) == 1 + # The four .nc files survive, root.txt is filtered as INVALID + assert len(df) == 4 assert "INVALID_ASSET" not in df.columns assert "TRACEBACK" not in df.columns @@ -194,7 +183,6 @@ def test_empty_directory_raises(self, empty_dir): paths=[str(empty_dir)], parsing_func=_good_parser, include_patterns=["*.nc"], - depth=5, ) def test_all_invalid_returns_empty(self, tmp_tree): @@ -206,7 +194,6 @@ def _all_invalid(file: str, **kwargs: Any) -> dict[str, Any]: paths=[str(tmp_tree)], parsing_func=_all_invalid, include_patterns=["*.nc"], - depth=10, ) assert df.empty @@ -223,7 +210,7 @@ class TestParallelParsingSafety: def test_parse_files_runs_in_worker_processes(self, tmp_path): """n_jobs > 1 must execute the parser out-of-process, not in threads.""" root = _flat_tree(tmp_path, n=8) - assets = discover_files([str(root)], include_patterns=["*.nc"], depth=5) + assets = discover_files([str(root)], include_patterns=["*.nc"]) results = parse_files(assets, _pid_parser, n_jobs=2) @@ -236,7 +223,7 @@ def test_parse_files_runs_in_worker_processes(self, tmp_path): def test_parse_files_sequential_runs_in_process(self, tmp_path): """n_jobs == 1 stays in-process (no pool overhead).""" root = _flat_tree(tmp_path, n=4) - assets = discover_files([str(root)], include_patterns=["*.nc"], depth=5) + assets = discover_files([str(root)], include_patterns=["*.nc"]) results = parse_files(assets, _pid_parser, n_jobs=1) @@ -260,7 +247,6 @@ def test_complete_parser_parallel_does_not_crash(self, tmp_path, n_jobs): paths=[str(root)], parsing_func=parse_cmip6_complete, include_patterns=["*.nc"], - depth=5, n_jobs=n_jobs, ) @@ -279,7 +265,6 @@ def test_complete_parser_parallel_matches_sequential(self, tmp_path): paths=[str(root)], parsing_func=parse_cmip6_complete, include_patterns=["*.nc"], - depth=5, ) sequential = build_catalog(n_jobs=1, **kwargs).sort_values("path").reset_index(drop=True) parallel = build_catalog(n_jobs=4, **kwargs).sort_values("path").reset_index(drop=True) @@ -311,7 +296,7 @@ def _wide_tree(tmp_path: Path, num_dirs: int, files_per_dir: int) -> Path: class TestIterDiscoveredChunks: def test_yields_all_files(self, tmp_path): root = _flat_tree(tmp_path, n=25) - chunks = list(iter_discovered_chunks([str(root)], include_patterns=["*.nc"], depth=5, chunk_size=10)) + chunks = list(iter_discovered_chunks([str(root)], include_patterns=["*.nc"], chunk_size=10)) flat = [p for chunk in chunks for p in chunk] assert len(flat) == 25 assert all(p.endswith(".nc") for p in flat) @@ -319,7 +304,7 @@ def test_yields_all_files(self, tmp_path): def test_chunk_size_respected_at_directory_boundaries(self, tmp_path): # 5 directories x 4 files = 20 files. chunk_size=8 forces splits between dirs. root = _wide_tree(tmp_path, num_dirs=5, files_per_dir=4) - chunks = list(iter_discovered_chunks([str(root)], include_patterns=["*.nc"], depth=5, chunk_size=8)) + chunks = list(iter_discovered_chunks([str(root)], include_patterns=["*.nc"], chunk_size=8)) # Every chunk groups whole directories together (no directory split across chunks). for chunk in chunks: dirs = {str(Path(p).parent) for p in chunk} @@ -334,14 +319,12 @@ def test_chunk_size_respected_at_directory_boundaries(self, tmp_path): def test_empty_root_yields_nothing(self, tmp_path): empty = tmp_path / "empty" empty.mkdir() - chunks = list(iter_discovered_chunks([str(empty)], include_patterns=["*.nc"], depth=5, chunk_size=10)) + chunks = list(iter_discovered_chunks([str(empty)], include_patterns=["*.nc"], chunk_size=10)) assert chunks == [] def test_single_file_path(self, tmp_tree): nc_file = tmp_tree / "root.nc" - chunks = list( - iter_discovered_chunks([str(nc_file)], include_patterns=["*.nc"], depth=0, chunk_size=10) - ) + chunks = list(iter_discovered_chunks([str(nc_file)], include_patterns=["*.nc"], chunk_size=10)) assert chunks == [[str(nc_file)]] @@ -353,7 +336,6 @@ def test_streams_chunks(self, tmp_path): paths=[str(root)], parsing_func=_good_parser, include_patterns=["*.nc"], - depth=5, n_jobs=1, chunk_size=5, ) @@ -373,7 +355,6 @@ def test_invalid_rows_filtered_per_chunk(self, tmp_tree): paths=[str(tmp_tree)], parsing_func=_mixed_parser, include_patterns=["*.nc", "*.txt"], - depth=10, chunk_size=2, ) ) @@ -392,7 +373,6 @@ def test_empty_input_yields_nothing(self, tmp_path): paths=[str(empty)], parsing_func=_good_parser, include_patterns=["*.nc"], - depth=5, chunk_size=10, ) ) @@ -405,7 +385,6 @@ def test_chunk_larger_than_total_yields_single_chunk(self, tmp_path): paths=[str(root)], parsing_func=_good_parser, include_patterns=["*.nc"], - depth=5, n_jobs=1, chunk_size=100, ) @@ -423,7 +402,6 @@ def _all_invalid(file: str, **kwargs: Any) -> dict[str, Any]: paths=[str(tmp_tree)], parsing_func=_all_invalid, include_patterns=["*.nc"], - depth=10, chunk_size=2, ) ) @@ -438,7 +416,6 @@ def test_no_invalid_column_passes_through(self, tmp_path): paths=[str(root)], parsing_func=_good_parser, include_patterns=["*.nc"], - depth=5, chunk_size=2, ) ) @@ -453,7 +430,6 @@ def test_iter_discovered_chunks_skips_nonexistent_paths(self, tmp_path): iter_discovered_chunks( ["/does/not/exist", str(root)], include_patterns=["*.nc"], - depth=5, chunk_size=10, ) ) @@ -467,7 +443,7 @@ def test_iter_discovered_chunks_directory_overflow_kept_together(self, tmp_path) for i in range(6): (root / f"f_{i}.nc").touch() - chunks = list(iter_discovered_chunks([str(root)], include_patterns=["*.nc"], depth=5, chunk_size=2)) + chunks = list(iter_discovered_chunks([str(root)], include_patterns=["*.nc"], chunk_size=2)) # All six files come from one directory; the buffer flushes once at the end. assert sum(len(c) for c in chunks) == 6 for chunk in chunks: @@ -482,8 +458,6 @@ def test_iter_discovered_chunks_multiple_roots(self, tmp_path): b.mkdir() (b / "2.nc").touch() - chunks = list( - iter_discovered_chunks([str(a), str(b)], include_patterns=["*.nc"], depth=5, chunk_size=10) - ) + chunks = list(iter_discovered_chunks([str(a), str(b)], include_patterns=["*.nc"], chunk_size=10)) flat = [p for chunk in chunks for p in chunk] assert len(flat) == 2 diff --git a/packages/climate-ref/tests/unit/datasets/test_cmip7.py b/packages/climate-ref/tests/unit/datasets/test_cmip7.py index 40b668ec3..9bbef594c 100644 --- a/packages/climate-ref/tests/unit/datasets/test_cmip7.py +++ b/packages/climate-ref/tests/unit/datasets/test_cmip7.py @@ -284,9 +284,7 @@ def test_streaming_matches_whole_tree(self, tmp_path, config): config.cmip7_parser = "drs" adapter = CMIP7DatasetAdapter(config=config) _build_cmip7_archive(tmp_path / "archive", self.DATASETS) - # CMIP7DatasetAdapter walks with depth=10, so point it at the - # activity_id parent (MIP-DRS7/CMIP7) rather than the bare archive root. - root = tmp_path / "archive" / "MIP-DRS7" / "CMIP7" / "CMIP" + root = tmp_path / "archive" whole = adapter.find_local_datasets(root) streamed = pd.concat(list(adapter.iter_local_datasets(root, chunk_size=2))) @@ -296,6 +294,18 @@ def test_streaming_matches_whole_tree(self, tmp_path, config): sort_data_catalog(streamed.reset_index(drop=True)), ) + def test_finds_datasets_from_the_archive_root(self, tmp_path, config): + """Both entry points must reach files nested a full DRS below the given root.""" + config.cmip7_parser = "drs" + adapter = CMIP7DatasetAdapter(config=config) + _build_cmip7_archive(tmp_path / "archive", self.DATASETS) + root = tmp_path / "archive" + + expected = sum(len(dataset["time_ranges"]) for dataset in self.DATASETS) + + assert len(adapter.find_local_datasets(root)) == expected + assert sum(len(chunk) for chunk in adapter.iter_local_datasets(root)) == expected + def test_streaming_yields_nonempty_chunks(self, tmp_path, config): config.cmip7_parser = "drs" adapter = CMIP7DatasetAdapter(config=config) diff --git a/packages/climate-ref/tests/unit/datasets/test_obs4mips/obs4mips_catalog_db.yml b/packages/climate-ref/tests/unit/datasets/test_obs4mips/obs4mips_catalog_db.yml index 5fe46d4d5..6ffa0ac23 100644 --- a/packages/climate-ref/tests/unit/datasets/test_obs4mips/obs4mips_catalog_db.yml +++ b/packages/climate-ref/tests/unit/datasets/test_obs4mips/obs4mips_catalog_db.yml @@ -1,114 +1,3 @@ -- activity_id: obs4MIPs - end_time: '2012-12-15 00:00:00' - finalised: true - frequency: mon - grid: 0.5x0.5 degree - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.ARCCSS.LORA-1-1.mon.mrro.50km.gn.v20250516 - institution_id: ARCCSS - long_name: Total Runoff - nominal_resolution: 50 km - path: '{esgf_data_dir}/obs4REF/obs4REF/ARCCSS/LORA-1-1/mon/mrro/gn/20250516/mrro_mon_LORA-1-1_REF_gn_198001-201212.nc' - product: observations - realm: land - source_id: LORA-1-1 - source_type: gridded_insitu - source_version_number: '1.1' - start_time: '1980-01-15 00:00:00' - units: kg m-2 s-1 - variable_id: mrro - variant_label: REF - version: v20250516 - vertical_levels: 1 -- activity_id: obs4MIPs - end_time: '2019-12-16 12:00:00' - finalised: true - frequency: mon - grid: 1x1 degree latitude x longitude - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.CNES.AVISO-1-0.mon.zos.250km.gn.v20210727 - institution_id: CNES - long_name: Sea Surface Height Above Geoid - nominal_resolution: 250 km - path: '{esgf_data_dir}/obs4REF/obs4REF/CNES/AVISO-1-0/mon/zos/gn/v20210727/zos_mon_AVISO-1-0_PCMDI_gn_199301-201912.nc' - product: observations - realm: ocean - source_id: AVISO-1-0 - source_type: satellite_retrieval - source_version_number: '1.0' - start_time: '1993-01-16 12:00:00' - units: m - variable_id: zos - variant_label: PCMDI - version: v20210727 - vertical_levels: 1 -- activity_id: obs4MIPs - end_time: '2015-12-15 00:00:00' - finalised: true - frequency: mon - grid: 1x1 degree - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.ColumbiaU.WECANN-1-0.mon.gpp.100km.gn.v20250516 - institution_id: ColumbiaU - long_name: Carbon Mass Flux out of Atmosphere Due to Gross Primary Production on - Land [kgC m-2 s-1] - nominal_resolution: 100 km - path: '{esgf_data_dir}/obs4REF/obs4REF/ColumbiaU/WECANN-1-0/mon/gpp/gn/20250516/gpp_mon_WECANN-1-0_REF_gn_200701-201512.nc' - product: derived - realm: land - source_id: WECANN-1-0 - source_type: satellite_retrieval - source_version_number: '1' - start_time: '2007-01-15 00:00:00' - units: kg m-2 s-1 - variable_id: gpp - variant_label: REF - version: v20250516 - vertical_levels: 1 -- activity_id: obs4MIPs - end_time: '2015-12-15 00:00:00' - finalised: true - frequency: mon - grid: 1x1 degree - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.ColumbiaU.WECANN-1-0.mon.hfls.100km.gn.v20250516 - institution_id: ColumbiaU - long_name: Surface Upward Latent Heat Flux - nominal_resolution: 100 km - path: '{esgf_data_dir}/obs4REF/obs4REF/ColumbiaU/WECANN-1-0/mon/hfls/gn/20250516/hfls_mon_WECANN-1-0_REF_gn_200701-201512.nc' - product: derived - realm: atmos - source_id: WECANN-1-0 - source_type: satellite_retrieval - source_version_number: '1' - start_time: '2007-01-15 00:00:00' - units: W m-2 - variable_id: hfls - variant_label: REF - version: v20250516 - vertical_levels: 1 -- activity_id: obs4MIPs - end_time: '2015-12-15 00:00:00' - finalised: true - frequency: mon - grid: 1x1 degree - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.ColumbiaU.WECANN-1-0.mon.hfss.100km.gn.v20250516 - institution_id: ColumbiaU - long_name: Surface Upward Sensible Heat Flux - nominal_resolution: 100 km - path: '{esgf_data_dir}/obs4REF/obs4REF/ColumbiaU/WECANN-1-0/mon/hfss/gn/20250516/hfss_mon_WECANN-1-0_REF_gn_200701-201512.nc' - product: derived - realm: atmos - source_id: WECANN-1-0 - source_type: satellite_retrieval - source_version_number: '1' - start_time: '2007-01-15 00:00:00' - units: W m-2 - variable_id: hfss - variant_label: REF - version: v20250516 - vertical_levels: 1 - activity_id: obs4MIPs end_time: '2021-12-16 12:00:00' finalised: true @@ -2639,579 +2528,3 @@ variant_label: PCMDI version: v20250220 vertical_levels: 37 -- activity_id: obs4MIPs - end_time: '2017-07-16 12:00:00' - finalised: true - frequency: mon - grid: 1x1 degree latitude x longitude - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.ESSO.TropFlux-1-0.mon.hfls.250km.gn.v20250415 - institution_id: ESSO - long_name: Surface Upward Latent Heat Flux - nominal_resolution: 250 km - path: '{esgf_data_dir}/obs4REF/obs4REF/ESSO/TropFlux-1-0/mon/hfls/gn/v20250415/hfls_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc' - product: observations - realm: atmos - source_id: TropFlux-1-0 - source_type: satellite_blended - source_version_number: '1.0' - start_time: '1979-01-16 12:00:00' - units: W m-2 - variable_id: hfls - variant_label: PCMDI - version: v20250415 - vertical_levels: 1 -- activity_id: obs4MIPs - end_time: '2017-07-15 12:00:00' - finalised: true - frequency: mon - grid: 1.0x1.0 degree latitude x longitude - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.ESSO.TropFlux-1-0.mon.hfns.250km.gn.v20210727 - institution_id: ESSO - long_name: Net Surface Energy - nominal_resolution: 250 km - path: '{esgf_data_dir}/obs4REF/obs4REF/ESSO/TropFlux-1-0/mon/hfns/gn/v20210727/hfns_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc' - product: observations - realm: atmos - source_id: TropFlux-1-0 - source_type: satellite_blended - source_version_number: '1.0' - start_time: '1979-01-15 00:00:00' - units: W m-2 - variable_id: hfns - variant_label: PCMDI - version: v20210727 - vertical_levels: 1 -- activity_id: obs4MIPs - end_time: '2017-07-16 12:00:00' - finalised: true - frequency: mon - grid: 1x1 degree latitude x longitude - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.ESSO.TropFlux-1-0.mon.hfss.250km.gn.v20250415 - institution_id: ESSO - long_name: Surface Upward Sensible Heat Flux - nominal_resolution: 250 km - path: '{esgf_data_dir}/obs4REF/obs4REF/ESSO/TropFlux-1-0/mon/hfss/gn/v20250415/hfss_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc' - product: observations - realm: atmos - source_id: TropFlux-1-0 - source_type: satellite_blended - source_version_number: '1.0' - start_time: '1979-01-16 12:00:00' - units: W m-2 - variable_id: hfss - variant_label: PCMDI - version: v20250415 - vertical_levels: 1 -- activity_id: obs4MIPs - end_time: '2017-07-16 12:00:00' - finalised: true - frequency: mon - grid: 1x1 degree latitude x longitude - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.ESSO.TropFlux-1-0.mon.tas.250km.gn.v20250415 - institution_id: ESSO - long_name: Near-Surface Air Temperature - nominal_resolution: 250 km - path: '{esgf_data_dir}/obs4REF/obs4REF/ESSO/TropFlux-1-0/mon/tas/gn/v20250415/tas_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc' - product: observations - realm: atmos - source_id: TropFlux-1-0 - source_type: satellite_blended - source_version_number: '1.0' - start_time: '1979-01-16 12:00:00' - units: K - variable_id: tas - variant_label: PCMDI - version: v20250415 - vertical_levels: 1 -- activity_id: obs4MIPs - end_time: '2017-07-16 12:00:00' - finalised: true - frequency: mon - grid: 1x1 degree latitude x longitude - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.ESSO.TropFlux-1-0.mon.tauu.250km.gn.v20250415 - institution_id: ESSO - long_name: Surface Downward Eastward Wind Stress - nominal_resolution: 250 km - path: '{esgf_data_dir}/obs4REF/obs4REF/ESSO/TropFlux-1-0/mon/tauu/gn/v20250415/tauu_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc' - product: observations - realm: atmos - source_id: TropFlux-1-0 - source_type: satellite_blended - source_version_number: '1.0' - start_time: '1979-01-16 12:00:00' - units: Pa - variable_id: tauu - variant_label: PCMDI - version: v20250415 - vertical_levels: 1 -- activity_id: obs4MIPs - end_time: '2017-07-15 12:00:00' - finalised: true - frequency: mon - grid: 1.0x1.0 degree latitude x longitude - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.ESSO.TropFlux-1-0.mon.tauv.250km.gn.v20210727 - institution_id: ESSO - long_name: Surface Downward Northward Wind Stress - nominal_resolution: 250 km - path: '{esgf_data_dir}/obs4REF/obs4REF/ESSO/TropFlux-1-0/mon/tauv/gn/v20210727/tauv_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc' - product: observations - realm: atmos - source_id: TropFlux-1-0 - source_type: satellite_blended - source_version_number: '1.0' - start_time: '1979-01-15 00:00:00' - units: Pa - variable_id: tauv - variant_label: PCMDI - version: v20210727 - vertical_levels: 1 -- activity_id: obs4MIPs - end_time: '2017-07-15 12:00:00' - finalised: true - frequency: mon - grid: 1.0x1.0 degree latitude x longitude - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.ESSO.TropFlux-1-0.mon.ts.250km.gn.v20210727 - institution_id: ESSO - long_name: Surface Temperature - nominal_resolution: 250 km - path: '{esgf_data_dir}/obs4REF/obs4REF/ESSO/TropFlux-1-0/mon/ts/gn/v20210727/ts_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc' - product: observations - realm: atmos - source_id: TropFlux-1-0 - source_type: satellite_blended - source_version_number: '1.0' - start_time: '1979-01-15 00:00:00' - units: K - variable_id: ts - variant_label: PCMDI - version: v20210727 - vertical_levels: 1 -- activity_id: obs4MIPs - end_time: '2025-01-16 12:00:00' - finalised: true - frequency: mon - grid: 1x1 degree latitude x longitude - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 - institution_id: MOHC - long_name: Surface Temperature - nominal_resolution: 250 km - path: '{esgf_data_dir}/obs4REF/obs4REF/MOHC/HadISST-1-1/mon/ts/gn/v20250415/ts_mon_HadISST-1-1_PCMDI_gn_187001-202501.nc' - product: observations - realm: atmos - source_id: HadISST-1-1 - source_type: satellite_blended - source_version_number: 1-1 - start_time: '1870-01-16 12:00:00' - units: K - variable_id: ts - variant_label: PCMDI - version: v20250415 - vertical_levels: 1 -- activity_id: obs4MIPs - end_time: '2023-03-16 12:00:00' - finalised: true - frequency: mon - grid: 0.5x0.5 degree latitude x longitude - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NASA-GSFC.GPCP-Monthly-3-2.mon.pr.50km.gn.v20231205 - institution_id: NASA-GSFC - long_name: Precipitation - nominal_resolution: 50 km - path: '{esgf_data_dir}/obs4REF/obs4REF/NOAA-NCEI/GPCP-2-3/mon/pr/gn/v20231205/pr_mon_GPCP-Monthly-3-2_RSS_gn_198301-202303.nc' - product: observations - realm: atmos - source_id: GPCP-Monthly-3-2 - source_type: satellite_blended - source_version_number: '3.2' - start_time: '1983-01-16 12:00:00' - units: kg m-2 s-1 - variable_id: pr - variant_label: RSS - version: v20231205 - vertical_levels: 1 -- activity_id: obs4MIPs - end_time: '2017-12-16 12:00:00' - finalised: true - frequency: mon - grid: 0.25x0.25 degree latitude x longitude - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NASA-GSFC.TRMM-3B43v-7.mon.pr.25km.gn.v20210727 - institution_id: NASA-GSFC - long_name: Precipitation - nominal_resolution: 25 km - path: '{esgf_data_dir}/obs4REF/obs4REF/NASA-GSFC/TRMM-3B43v-7/mon/pr/gn/v20210727/pr_mon_TRMM-3B43v-7_PCMDI_gn_199801-201712.nc' - product: observations - realm: atmos - source_id: TRMM-3B43v-7 - source_type: satellite_blended - source_version_number: 3B43v.7 - start_time: '1998-01-16 12:00:00' - units: kg m-2 s-1 - variable_id: pr - variant_label: PCMDI - version: v20210727 - vertical_levels: 1 -- activity_id: obs4MIPs - end_time: '2023-09-16 00:00:00' - finalised: true - frequency: mon - grid: 1x1 degree latitude x longitude - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NASA-LaRC.CERES-EBAF-4-2.mon.rlds.100km.gn.v20230209 - institution_id: NASA-LaRC - long_name: Surface Downwelling Longwave Radiation - nominal_resolution: 100 km - path: '{esgf_data_dir}/obs4REF/obs4REF/NASA-LaRC/CERES-EBAF-4-2/mon/rlds/gn/v20230209/rlds_mon_CERES-EBAF-4-2_RSS_gn_200003-202309.nc' - product: observations - realm: atmos - source_id: CERES-EBAF-4-2 - source_type: satellite_blended - source_version_number: '4.2' - start_time: '2000-03-16 12:00:00' - units: W m-2 - variable_id: rlds - variant_label: RSS - version: v20230209 - vertical_levels: 1 -- activity_id: obs4MIPs - end_time: '2023-09-16 00:00:00' - finalised: true - frequency: mon - grid: 1x1 degree latitude x longitude - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NASA-LaRC.CERES-EBAF-4-2.mon.rlus.100km.gn.v20230209 - institution_id: NASA-LaRC - long_name: Surface Upwelling Longwave Radiation - nominal_resolution: 100 km - path: '{esgf_data_dir}/obs4REF/obs4REF/NASA-LaRC/CERES-EBAF-4-2/mon/rlus/gn/v20230209/rlus_mon_CERES-EBAF-4-2_RSS_gn_200003-202309.nc' - product: observations - realm: atmos - source_id: CERES-EBAF-4-2 - source_type: satellite_blended - source_version_number: '4.2' - start_time: '2000-03-16 12:00:00' - units: W m-2 - variable_id: rlus - variant_label: RSS - version: v20230209 - vertical_levels: 1 -- activity_id: obs4MIPs - end_time: '2023-09-16 00:00:00' - finalised: true - frequency: mon - grid: 1x1 degree latitude x longitude - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NASA-LaRC.CERES-EBAF-4-2.mon.rsds.100km.gn.v20230209 - institution_id: NASA-LaRC - long_name: Surface Downwelling Shortwave Radiation - nominal_resolution: 100 km - path: '{esgf_data_dir}/obs4REF/obs4REF/NASA-LaRC/CERES-EBAF-4-2/mon/rsds/gn/v20230209/rsds_mon_CERES-EBAF-4-2_RSS_gn_200003-202309.nc' - product: observations - realm: atmos - source_id: CERES-EBAF-4-2 - source_type: satellite_blended - source_version_number: '4.2' - start_time: '2000-03-16 12:00:00' - units: W m-2 - variable_id: rsds - variant_label: RSS - version: v20230209 - vertical_levels: 1 -- activity_id: obs4MIPs - end_time: '2023-09-16 00:00:00' - finalised: true - frequency: mon - grid: 1x1 degree latitude x longitude - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NASA-LaRC.CERES-EBAF-4-2.mon.rsus.100km.gn.v20230209 - institution_id: NASA-LaRC - long_name: Surface Upwelling Shortwave Radiation - nominal_resolution: 100 km - path: '{esgf_data_dir}/obs4REF/obs4REF/NASA-LaRC/CERES-EBAF-4-2/mon/rsus/gn/v20230209/rsus_mon_CERES-EBAF-4-2_RSS_gn_200003-202309.nc' - product: observations - realm: atmos - source_id: CERES-EBAF-4-2 - source_type: satellite_blended - source_version_number: '4.2' - start_time: '2000-03-16 12:00:00' - units: W m-2 - variable_id: rsus - variant_label: RSS - version: v20230209 - vertical_levels: 1 -- activity_id: obs4MIPs - end_time: '2012-12-16 12:00:00' - finalised: true - frequency: mon - grid: 2.0x2.0 degree latitude x longitude - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NOAA-ESRL-PSD.20CR.mon.psl.250km.gn.v20210727 - institution_id: NOAA-ESRL-PSD - long_name: Sea Level Pressure - nominal_resolution: 250 km - path: '{esgf_data_dir}/obs4REF/obs4REF/NOAA-ESRL-PSD/20CR/mon/psl/gn/v20210727/psl_mon_20CR_PCMDI_gn_187101-201212.nc' - product: observations - realm: atmos - source_id: 20CR - source_type: reanalysis - source_version_number: N/A - start_time: '1871-01-16 12:00:00' - units: Pa - variable_id: psl - variant_label: PCMDI - version: v20210727 - vertical_levels: 1 -- activity_id: obs4MIPs - end_time: '2012-12-16 12:00:00' - finalised: true - frequency: mon - grid: 2.0x2.0 degree latitude x longitude - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NOAA-ESRL-PSD.20CR.mon.ts.250km.gn.v20210727 - institution_id: NOAA-ESRL-PSD - long_name: Surface Temperature - nominal_resolution: 250 km - path: '{esgf_data_dir}/obs4REF/obs4REF/NOAA-ESRL-PSD/20CR/mon/ts/gn/v20210727/ts_mon_20CR_PCMDI_gn_187101-201212.nc' - product: observations - realm: atmos - source_id: 20CR - source_type: reanalysis - source_version_number: N/A - start_time: '1871-01-16 12:00:00' - units: K - variable_id: ts - variant_label: PCMDI - version: v20210727 - vertical_levels: 1 -- activity_id: obs4MIPs - end_time: '2019-01-16 12:00:00' - finalised: true - frequency: mon - grid: 0.25x0.25 degree latitude x longitude - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NOAA-NCEI.CMAP-V1902.mon.pr.100km.gn.v20210727 - institution_id: NOAA-NCEI - long_name: Precipitation - nominal_resolution: 100 km - path: '{esgf_data_dir}/obs4REF/obs4REF/NOAA-NCEI/CMAP-V1902/mon/pr/gn/v20210727/pr_mon_CMAP-V1902_PCMDI_gn_197901-201901.nc' - product: observations - realm: atmos - source_id: CMAP-V1902 - source_type: satellite_blended - source_version_number: V1902 - start_time: '1979-01-16 12:00:00' - units: kg m-2 s-1 - variable_id: pr - variant_label: PCMDI - version: v20210727 - vertical_levels: 1 -- activity_id: obs4MIPs - end_time: '2019-07-16 12:00:00' - finalised: true - frequency: mon - grid: 2.5x2.5 degree latitude x longitude - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NOAA-NCEI.GPCP-2-3.mon.pr.250km.gn.v20210727 - institution_id: NOAA-NCEI - long_name: Precipitation - nominal_resolution: 250 km - path: '{esgf_data_dir}/obs4REF/obs4REF/NOAA-NCEI/GPCP-2-3/mon/pr/gn/v20210727/pr_mon_GPCP-2-3_PCMDI_gn_197901-201907.nc' - product: observations - realm: atmos - source_id: GPCP-2-3 - source_type: satellite_blended - source_version_number: '2.3' - start_time: '1979-01-16 12:00:00' - units: kg m-2 s-1 - variable_id: pr - variant_label: PCMDI - version: v20210727 - vertical_levels: 1 -- activity_id: obs4MIPs - end_time: '2015-12-15 00:00:00' - finalised: true - frequency: mon - grid: 100 km - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NOAA-NCEI.WOA2023.mon.no3.100km.gn.v20250516 - institution_id: NOAA-NCEI - long_name: Objectively analyzed mean fields for moles_of_nitrate_per_unit_mass_in_sea_water - at standard depth levels. - nominal_resolution: 100 km - path: '{esgf_data_dir}/obs4REF/obs4REF/NOAA-NCEI/WOA2023/mon/no3/gn/20250516/no3_mon_WOA2023_REF_gn_201501-202212.nc' - product: observations - realm: ocean - source_id: WOA2023 - source_type: gridded_insitu - source_version_number: '2023' - start_time: '2015-01-15 00:00:00' - units: micromoles_per_kilogram - variable_id: no3 - variant_label: REF - version: v20250516 - vertical_levels: 43 -- activity_id: obs4MIPs - end_time: '2015-12-15 00:00:00' - finalised: true - frequency: mon - grid: 100 km - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NOAA-NCEI.WOA2023.mon.o2.100km.gn.v20250516 - institution_id: NOAA-NCEI - long_name: Objectively analyzed mean fields for moles_of_oxygen_per_unit_mass_in_sea_water - at standard depth levels. - nominal_resolution: 100 km - path: '{esgf_data_dir}/obs4REF/obs4REF/NOAA-NCEI/WOA2023/mon/o2/gn/20250516/o2_mon_WOA2023_REF_gn_201501-202212.nc' - product: observations - realm: ocean - source_id: WOA2023 - source_type: gridded_insitu - source_version_number: '2023' - start_time: '2015-01-15 00:00:00' - units: micromoles_per_kilogram - variable_id: o2 - variant_label: REF - version: v20250516 - vertical_levels: 57 -- activity_id: obs4MIPs - end_time: '2015-12-15 00:00:00' - finalised: true - frequency: mon - grid: 100 km - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NOAA-NCEI.WOA2023.mon.po4.100km.gn.v20250516 - institution_id: NOAA-NCEI - long_name: Objectively analyzed mean fields for moles_of_phosphate_per_unit_mass_in_sea_water - at standard depth levels. - nominal_resolution: 100 km - path: '{esgf_data_dir}/obs4REF/obs4REF/NOAA-NCEI/WOA2023/mon/po4/gn/20250516/po4_mon_WOA2023_REF_gn_201501-202212.nc' - product: observations - realm: ocean - source_id: WOA2023 - source_type: gridded_insitu - source_version_number: '2023' - start_time: '2015-01-15 00:00:00' - units: micromoles_per_kilogram - variable_id: po4 - variant_label: REF - version: v20250516 - vertical_levels: 43 -- activity_id: obs4MIPs - end_time: '2015-12-15 00:00:00' - finalised: true - frequency: mon - grid: 100 km - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NOAA-NCEI.WOA2023.mon.so.100km.gn.v20250516 - institution_id: NOAA-NCEI - long_name: Objectively analyzed mean fields for sea_water_practical_salinity at - standard depth levels. - nominal_resolution: 100 km - path: '{esgf_data_dir}/obs4REF/obs4REF/NOAA-NCEI/WOA2023/mon/so/gn/20250516/so_mon_WOA2023_REF_gn_201501-202212.nc' - product: observations - realm: ocean - source_id: WOA2023 - source_type: gridded_insitu - source_version_number: '2023' - start_time: '2015-01-15 00:00:00' - units: '1' - variable_id: so - variant_label: REF - version: v20250516 - vertical_levels: 57 -- activity_id: obs4MIPs - end_time: '2015-12-15 00:00:00' - finalised: true - frequency: mon - grid: 100 km - grid_label: gn - instance_id: obs4MIPs.obs4MIPs.NOAA-NCEI.WOA2023.mon.thetao.100km.gn.v20250516 - institution_id: NOAA-NCEI - long_name: Sea Water Potential Temperature - nominal_resolution: 100 km - path: '{esgf_data_dir}/obs4REF/obs4REF/NOAA-NCEI/WOA2023/mon/thetao/gn/20250516/thetao_mon_WOA2023_REF_gn_201501-202212.nc' - product: observations - realm: ocean - source_id: WOA2023 - source_type: gridded_insitu - source_version_number: '2023' - start_time: '2015-01-15 00:00:00' - units: degC - variable_id: thetao - variant_label: REF - version: v20250516 - vertical_levels: 57 -- activity_id: obs4MIPs - end_time: '2023-02-15 00:00:00' - finalised: true - frequency: mon - grid: N/A - grid_label: NA - instance_id: obs4MIPs.obs4MIPs.NOC.RAPID.mon.msftmz.N/A.NA.v20250516 - institution_id: NOC - long_name: Ocean Meridional Overturning Mass Streamfunction - nominal_resolution: N/A - path: '{esgf_data_dir}/obs4REF/obs4REF/NOC/RAPID/mon/msftmz/NA/20250516/msftmz_mon_RAPID_REF_NA_200404-202302.nc' - product: derived - realm: ocean - source_id: RAPID - source_type: insitu - source_version_number: '2023.1' - start_time: '2004-04-15 00:00:00' - units: Sv - variable_id: msftmz - variant_label: REF - version: v20250516 - vertical_levels: 1 -- activity_id: obs4MIPs - end_time: '2010-07-02 12:00:00' - finalised: true - frequency: yr - grid: global mean data - grid_label: gm - instance_id: obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman.yr.fgco2.N/A.gm.v20250516 - institution_id: UCI-ORNL - long_name: global net downward ocean carbon flux - nominal_resolution: N/A - path: '{esgf_data_dir}/obs4REF/obs4REF/UCI-ORNL/Hoffman/yr/fgco2/gm/20250516/fgco2_yr_Hoffman_REF_gm_185007-201007.nc' - product: derived - realm: ocean - source_id: Hoffman - source_type: stastical-estimate - source_version_number: '1' - start_time: '1850-07-02 12:00:00' - units: Pg yr-1 - variable_id: fgco2 - variant_label: REF - version: v20250516 - vertical_levels: 1 -- activity_id: obs4MIPs - end_time: '2010-07-02 12:00:00' - finalised: true - frequency: yr - grid: global mean data - grid_label: gm - instance_id: obs4MIPs.obs4MIPs.UCI-ORNL.Hoffman.yr.nbp.N/A.gm.v20250516 - institution_id: UCI-ORNL - long_name: global net downward land carbon flux - nominal_resolution: N/A - path: '{esgf_data_dir}/obs4REF/obs4REF/UCI-ORNL/Hoffman/yr/nbp/gm/20250516/nbp_yr_Hoffman_REF_gm_185007-201007.nc' - product: derived - realm: land - source_id: Hoffman - source_type: stastical-estimate - source_version_number: '1' - start_time: '1850-07-02 12:00:00' - units: Pg yr-1 - variable_id: nbp - variant_label: REF - version: v20250516 - vertical_levels: 1 diff --git a/packages/climate-ref/tests/unit/datasets/test_obs4ref.py b/packages/climate-ref/tests/unit/datasets/test_obs4ref.py index 0b770faab..aff40c8ec 100644 --- a/packages/climate-ref/tests/unit/datasets/test_obs4ref.py +++ b/packages/climate-ref/tests/unit/datasets/test_obs4ref.py @@ -1,10 +1,4 @@ -"""Tests for the obs4REF adapter (A3): warn-only cross-adapter enforcement. - -``Obs4REFDatasetAdapter`` and ``Obs4MIPsDatasetAdapter`` share the same -:func:`~climate_ref.datasets.obs4mips.parse_obs4mips` parser, but each restricts its own -``accepted_activity_ids``. A file whose ``activity_id`` doesn't match the adapter that -parses it is still ingested (warn-only, not rejected) -- see ``obs4mips.py`` docstrings. -""" +"""Tests for the obs4REF adapter.""" import netCDF4 import numpy as np @@ -45,43 +39,45 @@ def _write_obs4_style_file(path, *, activity_id: str) -> None: @pytest.fixture def obs4ref_style_dir(tmp_path): - """A single obs4REF-DRS-shaped file with ``activity_id="obs4REF"``.""" + """An obs4REF-registry-shaped file that still claims ``activity_id="obs4MIPs"`` inside.""" fixture_dir = tmp_path / "obs4ref_style" _write_obs4_style_file( fixture_dir / "obs4REF" / "TESTORG" / "TEST-SRC" / "mon" / "ts" / "gn" / "v1" / "ts_mon.nc", - activity_id="obs4REF", + activity_id="obs4MIPs", ) return fixture_dir class TestObs4REFDatasetAdapter: - def test_instance_id_prefix(self): - assert Obs4REFDatasetAdapter.instance_id_prefix == "obs4REF" - assert Obs4REFDatasetAdapter.accepted_activity_ids == ("obs4REF",) + def test_activity_id(self): + assert Obs4REFDatasetAdapter.activity_id == "obs4REF" + assert Obs4MIPsDatasetAdapter.activity_id == "obs4MIPs" - def test_load_local_datasets_prefixes_instance_id(self, obs4ref_style_dir): - adapter = Obs4REFDatasetAdapter() - data_catalog = adapter.find_local_datasets(obs4ref_style_dir) + def test_stamps_collection_regardless_of_file(self, obs4ref_style_dir): + """The registry republishes obs4MIPs files unchanged, so the adapter decides the collection.""" + data_catalog = Obs4REFDatasetAdapter().find_local_datasets(obs4ref_style_dir) assert len(data_catalog) == 1 - assert data_catalog["instance_id"].iloc[0].startswith("obs4REF.") - - def test_cross_parsed_by_obs4mips_adapter_warns_and_ingests(self, obs4ref_style_dir, caplog): - """An obs4REF file parsed by the obs4MIPs adapter is still ingested, with a warning.""" - obs4mips_adapter = Obs4MIPsDatasetAdapter() - ref_adapter = Obs4REFDatasetAdapter() + assert data_catalog["activity_id"].iloc[0] == "obs4REF" + assert data_catalog["instance_id"].iloc[0] == "obs4REF.obs4REF.TESTORG.TEST-SRC.mon.ts.100km.gn.v1" - obs4mips_catalog = obs4mips_adapter.find_local_datasets(obs4ref_style_dir) - ref_catalog = ref_adapter.find_local_datasets(obs4ref_style_dir) + def test_same_file_gets_distinct_ids(self, obs4ref_style_dir): + obs4mips_catalog = Obs4MIPsDatasetAdapter().find_local_datasets(obs4ref_style_dir) + ref_catalog = Obs4REFDatasetAdapter().find_local_datasets(obs4ref_style_dir) - assert len(obs4mips_catalog) == 1 obs4mips_instance_id = obs4mips_catalog["instance_id"].iloc[0] ref_instance_id = ref_catalog["instance_id"].iloc[0] + assert obs4mips_instance_id.startswith("obs4MIPs.obs4MIPs.") + assert ref_instance_id.startswith("obs4REF.obs4REF.") + assert obs4mips_instance_id.split(".", 2)[2] == ref_instance_id.split(".", 2)[2] + + def test_obs4mips_adapter_warns_on_obs4ref_layout(self, obs4ref_style_dir, caplog): + Obs4MIPsDatasetAdapter().find_local_datasets(obs4ref_style_dir) + + warnings = [r.message for r in caplog.records if r.levelname == "WARNING"] + assert any("look like obs4REF data" in msg and "--source-type obs4ref" in msg for msg in warnings) - assert obs4mips_instance_id.startswith("obs4MIPs.") - assert ref_instance_id.startswith("obs4REF.") - # Non-colliding slugs -- the cross-parsed file never masquerades as the same dataset. - assert obs4mips_instance_id != ref_instance_id + def test_obs4ref_adapter_does_not_warn(self, obs4ref_style_dir, caplog): + Obs4REFDatasetAdapter().find_local_datasets(obs4ref_style_dir) - warning_messages = [r.message for r in caplog.records if r.levelname == "WARNING"] - assert any("outside the expected" in msg for msg in warning_messages) + assert not [r for r in caplog.records if r.levelname == "WARNING"] diff --git a/packages/climate-ref/tests/unit/test_config.py b/packages/climate-ref/tests/unit/test_config.py index c2edeb509..089ae049b 100644 --- a/packages/climate-ref/tests/unit/test_config.py +++ b/packages/climate-ref/tests/unit/test_config.py @@ -226,6 +226,11 @@ def test_defaults(self, monkeypatch, mocker): "bucket": "ref-baselines-public", "cache_dir": str(resolve_cache_dir("native-baselines")), }, + "report_store": { + "url": "https://reports.baselines.climate-ref.org", + "s3_endpoint_url": "https://2aa5172b2bba093c516027d6fa13cdc8.r2.cloudflarestorage.com", + "bucket": "ref-baselines-reports", + }, "paths": { "log": f"{default_path}/log", "results": f"{default_path}/results", @@ -256,6 +261,19 @@ def test_from_env_variables(self, monkeypatch, config): assert config_new.paths.results == Path("/my/test/executions") assert config_new.cmip6_parser == "drs" + def test_report_store_defaults(self, config): + assert config.report_store.url == "https://reports.baselines.climate-ref.org" + assert config.report_store.bucket == "ref-baselines-reports" + + def test_report_store_from_env_variables(self, monkeypatch, config): + monkeypatch.setenv("REF_REPORT_STORE_URL", "file:///tmp/ref-reports") + monkeypatch.setenv("REF_REPORT_STORE_BUCKET", "staging-reports") + + config_new = config.refresh() + + assert config_new.report_store.url == "file:///tmp/ref-reports" + assert config_new.report_store.bucket == "staging-reports" + def test_measure_resources_defaults_on(self, config): assert config.executor.measure_resources is True diff --git a/packages/climate-ref/tests/unit/test_database.py b/packages/climate-ref/tests/unit/test_database.py index e86cfb834..1f3ac8a81 100644 --- a/packages/climate-ref/tests/unit/test_database.py +++ b/packages/climate-ref/tests/unit/test_database.py @@ -556,14 +556,14 @@ class TestReadOnlyDatabase: def test_make_readonly_sqlite_url_rewrites_file_url(self): url, connect_args = _make_readonly_sqlite_url("sqlite:////tmp/foo.db") - assert url == "sqlite:///file:/tmp/foo.db?mode=ro&immutable=1&uri=true" + assert url == "sqlite:///file:/tmp/foo.db?mode=ro&uri=true" assert connect_args == {"uri": True} def test_make_readonly_sqlite_url_preserves_percent_encoding(self): """Percent-encoded characters must survive the rewrite unchanged.""" original = "sqlite:///path%20with%20spaces/db.sqlite" url, connect_args = _make_readonly_sqlite_url(original) - assert url == "sqlite:///file:path%20with%20spaces/db.sqlite?mode=ro&immutable=1&uri=true" + assert url == "sqlite:///file:path%20with%20spaces/db.sqlite?mode=ro&uri=true" assert connect_args == {"uri": True} def test_make_readonly_sqlite_url_preserves_uri_form(self): @@ -589,7 +589,7 @@ def test_get_sqlite_path_returns_none_for_uri_form(self): def test_validate_accepts_uri_form_without_mkdir(self, tmp_path): """URI-form URLs are accepted verbatim and do not trigger parent mkdir.""" missing = tmp_path / "does-not-exist" / "foo.db" - url = f"sqlite:///file:{missing}?mode=ro&immutable=1&uri=true" + url = f"sqlite:///file:{missing}?mode=ro&uri=true" # Should not create the parent directory assert validate_database_url(url) == url diff --git a/packages/climate-ref/tests/unit/test_doctor.py b/packages/climate-ref/tests/unit/test_doctor.py index 56199066d..bb48663e2 100644 --- a/packages/climate-ref/tests/unit/test_doctor.py +++ b/packages/climate-ref/tests/unit/test_doctor.py @@ -7,6 +7,10 @@ import pandas as pd import pytest +from climate_ref_esmvaltool import provider as esmvaltool_provider +from climate_ref_example import provider as example_provider +from climate_ref_ilamb import provider as ilamb_provider +from climate_ref_pmp import provider as pmp_provider from climate_ref.doctor import ( DoctorContext, @@ -18,8 +22,11 @@ ) from climate_ref.doctor.checks.data import ( check_duplicate_coverage, + check_misfiled_obs4ref, check_missing_reference_data, + check_superseded_obs4ref, check_unreachable_source_types, + check_unsolvable_diagnostics, ) from climate_ref.doctor.registry import RegisteredCheck, run_checks from climate_ref_core.datasets import FacetFilter @@ -146,42 +153,273 @@ def test_ingested_dataset_is_not_reported(self): assert check_missing_reference_data(context) == [] def test_data_under_another_source_type_does_not_satisfy_a_requirement(self): - # The obs4ref trap: the data is present, but in a table no requirement reads. - provider = _provider_requiring(SourceDatasetType.obs4MIPs, "WECANN-1-0", "gpp") - catalog = _catalog( - [("obs4REF.WECANN-1-0.gpp", "WECANN-1-0", "gpp", "2007-01-01", "2015-12-01", "/d/gpp.nc")] - ) + # The data is present, but in a table the requirement does not read. + provider = _provider_requiring(SourceDatasetType.obs4MIPs, "ERA-5", "ta") + catalog = _catalog([("pmp.ERA-5.ta", "ERA-5", "ta", "2000-01-01", "2000-12-01", "/d/ta.nc")]) context = _context( - {SourceDatasetType.obs4MIPs: _catalog([]), SourceDatasetType.obs4REF: catalog}, + {SourceDatasetType.obs4MIPs: _catalog([]), SourceDatasetType.PMPClimatology: catalog}, [provider], ) findings = check_missing_reference_data(context) assert len(findings) == 1 - assert "WECANN-1-0" in findings[0].summary + assert "ERA-5" in findings[0].summary + + def test_obs4mips_requirement_is_met_by_obs4ref_data(self): + # obs4REF fills in what obs4MIPs has not published, so this is not missing. + provider = _provider_requiring(SourceDatasetType.obs4MIPs, "WECANN-1-0", "gpp") + catalog = _catalog( + [("obs4REF.WECANN-1-0.gpp", "WECANN-1-0", "gpp", "2007-01-01", "2015-12-01", "/d/gpp.nc")] + ) + context = _context({SourceDatasetType.obs4REF: catalog}, [provider]) + + assert check_missing_reference_data(context) == [] class TestUnreachableSourceTypes: def test_data_no_requirement_asks_for_is_reported(self): provider = _provider_requiring(SourceDatasetType.obs4MIPs, "ERA-5", "ta") + catalog = _catalog([("pmp.ERA-5.ta", "ERA-5", "ta", "2000-01-01", "2000-12-01", "/d/ta.nc")]) + context = _context({SourceDatasetType.PMPClimatology: catalog}, [provider]) + + findings = check_unreachable_source_types(context) + + assert len(findings) == 1 + assert "pmp-climatology" in findings[0].summary + assert "source type the diagnostics ask for" in findings[0].remedy + + def test_requested_source_type_is_not_reported(self): + provider = _provider_requiring(SourceDatasetType.obs4MIPs, "ERA-5", "ta") + catalog = _catalog([("obs4MIPs.ERA-5.ta", "ERA-5", "ta", "2000-01-01", "2000-12-01", "/d/ta.nc")]) + context = _context({SourceDatasetType.obs4MIPs: catalog}, [provider]) + + assert check_unreachable_source_types(context) == [] + + def test_obs4ref_data_is_reachable_through_obs4mips_requirements(self): + provider = _provider_requiring(SourceDatasetType.obs4MIPs, "WECANN-1-0", "gpp") catalog = _catalog( [("obs4REF.WECANN-1-0.gpp", "WECANN-1-0", "gpp", "2007-01-01", "2015-12-01", "/d/gpp.nc")] ) context = _context({SourceDatasetType.obs4REF: catalog}, [provider]) - findings = check_unreachable_source_types(context) + assert check_unreachable_source_types(context) == [] + + +class TestSupersededObs4ref: + def test_dataset_in_both_is_reported(self): + obs4mips = _catalog( + [ + ( + "obs4MIPs.obs4MIPs.C.WECANN-1-0.mon.gpp.gn.v2", + "WECANN-1-0", + "gpp", + "2007-01-01", + "2015-12-01", + "/a", + ) + ] + ) + obs4ref = _catalog( + [ + ( + "obs4REF.obs4REF.C.WECANN-1-0.mon.gpp.gn.v1", + "WECANN-1-0", + "gpp", + "2007-01-01", + "2015-12-01", + "/b", + ), + ( + "obs4REF.obs4REF.C.WECANN-1-0.mon.hfls.gn.v1", + "WECANN-1-0", + "hfls", + "2007-01-01", + "2015-12-01", + "/c", + ), + ] + ) + context = _context({SourceDatasetType.obs4MIPs: obs4mips, SourceDatasetType.obs4REF: obs4ref}) + + findings = check_superseded_obs4ref(context) assert len(findings) == 1 - assert "obs4ref" in findings[0].summary - assert "--source-type obs4mips" in findings[0].remedy + assert findings[0].severity == Severity.INFO + assert findings[0].summary.startswith("obs4REF.obs4REF.C.WECANN-1-0.mon.gpp.gn.v1") - def test_requested_source_type_is_not_reported(self): + def test_a_newer_obs4ref_version_is_not_superseded(self): + obs4mips = _catalog( + [ + ( + "obs4MIPs.obs4MIPs.C.WECANN-1-0.mon.gpp.gn.v1", + "WECANN-1-0", + "gpp", + "2007-01-01", + "2015-12-01", + "/a", + ) + ] + ) + obs4ref = _catalog( + [ + ( + "obs4REF.obs4REF.C.WECANN-1-0.mon.gpp.gn.v2", + "WECANN-1-0", + "gpp", + "2007-01-01", + "2015-12-01", + "/b", + ) + ] + ) + context = _context({SourceDatasetType.obs4MIPs: obs4mips, SourceDatasetType.obs4REF: obs4ref}) + + assert check_superseded_obs4ref(context) == [] + + def test_a_misfiled_row_does_not_supersede(self): + # Mid-upgrade both rows exist. Calling this superseded contradicts misfiled-obs4ref. + obs4mips = _catalog( + [ + ( + "obs4MIPs.obs4MIPs.C.WECANN-1-0.mon.gpp.gn.v2", + "WECANN-1-0", + "gpp", + "2007-01-01", + "2015-12-01", + "/d/obs4REF/C/gpp.nc", + ) + ] + ) + obs4ref = _catalog( + [ + ( + "obs4REF.obs4REF.C.WECANN-1-0.mon.gpp.gn.v1", + "WECANN-1-0", + "gpp", + "2007-01-01", + "2015-12-01", + "/d/obs4REF/C/gpp.nc", + ) + ] + ) + context = _context({SourceDatasetType.obs4MIPs: obs4mips, SourceDatasetType.obs4REF: obs4ref}) + + assert check_superseded_obs4ref(context) == [] + + def test_nothing_ingested(self): + assert check_superseded_obs4ref(_context()) == [] + + +class TestMisfiledObs4ref: + def test_obs4ref_layout_under_obs4mips_is_reported(self): + catalog = _catalog( + [ + ( + "obs4MIPs.obs4MIPs.X.gpp", + "X-1-0", + "gpp", + "2007-01-01", + "2015-12-01", + "/d/obs4REF/X/gpp.nc", + ), + ( + "obs4MIPs.obs4MIPs.ERA-5.ta", + "ERA-5", + "ta", + "2000-01-01", + "2000-12-01", + "/d/obs4MIPs/ta.nc", + ), + ] + ) + context = _context({SourceDatasetType.obs4MIPs: catalog}) + + findings = check_misfiled_obs4ref(context) + + assert len(findings) == 1 + assert findings[0].severity == Severity.WARNING + assert findings[0].summary == "obs4MIPs.obs4MIPs.X.gpp is obs4REF data ingested as obs4mips" + assert findings[0].command == "ref datasets ingest --source-type obs4ref " + + def test_each_misfiled_dataset_gets_its_own_finding(self): + catalog = _catalog( + [ + ( + "obs4MIPs.obs4MIPs.X.gpp", + "X-1-0", + "gpp", + "2007-01-01", + "2015-12-01", + "/d/obs4REF/X/gpp.nc", + ), + ("obs4MIPs.obs4MIPs.Y.ts", "Y-1-0", "ts", "2007-01-01", "2015-12-01", "/d/obs4REF/Y/ts.nc"), + ] + ) + context = _context({SourceDatasetType.obs4MIPs: catalog}) + + findings = check_misfiled_obs4ref(context) + + # One remedy shared across them, so the report groups them under it. + assert len(findings) == 2 + assert len({f.remedy for f in findings}) == 1 + + def test_registry_source_id_from_esgf_is_not_reported(self): + # HadISST-1-1 sits in both collections, so an ESGF copy is legitimately ingested as obs4MIPs. + catalog = _catalog( + [("obs4MIPs.obs4MIPs.HadISST.ts", "HadISST-1-1", "ts", "2000-01-01", "2000-12-01", "/d/ts.nc")] + ) + context = _context({SourceDatasetType.obs4MIPs: catalog}) + + assert check_misfiled_obs4ref(context) == [] + + def test_esgf_data_is_not_reported(self): + catalog = _catalog([("obs4MIPs.ERA-5.ta", "ERA-5", "ta", "2000-01-01", "2000-12-01", "/d/ta.nc")]) + context = _context({SourceDatasetType.obs4MIPs: catalog}) + + assert check_misfiled_obs4ref(context) == [] + + def test_nothing_ingested(self): + assert check_misfiled_obs4ref(_context()) == [] + + +class TestUnsolvableDiagnostics: + def test_diagnostic_with_nothing_ingested_is_reported(self): + provider = _provider_requiring(SourceDatasetType.obs4MIPs, "ERA-5", "ta") + context = _context({}, [provider]) + + findings = check_unsolvable_diagnostics(context) + + assert len(findings) == 1 + assert findings[0].severity == Severity.WARNING + assert "test_provider/needs-reference has no executions" == findings[0].summary + assert "nothing is ingested as obs4mips" in findings[0].detail + + def test_unmatched_filter_names_the_facets(self): + provider = _provider_requiring(SourceDatasetType.obs4MIPs, "ERA-5", "ta") + catalog = _catalog([("obs4MIPs.ERA-5.psl", "ERA-5", "psl", "2000-01-01", "2000-12-01", "/d/psl.nc")]) + context = _context({SourceDatasetType.obs4MIPs: catalog}, [provider]) + + findings = check_unsolvable_diagnostics(context) + + assert len(findings) == 1 + assert "no obs4mips datasets match source_id=ERA-5, variable_id=ta" in findings[0].detail + + def test_solvable_diagnostic_is_not_reported(self): provider = _provider_requiring(SourceDatasetType.obs4MIPs, "ERA-5", "ta") catalog = _catalog([("obs4MIPs.ERA-5.ta", "ERA-5", "ta", "2000-01-01", "2000-12-01", "/d/ta.nc")]) context = _context({SourceDatasetType.obs4MIPs: catalog}, [provider]) - assert check_unreachable_source_types(context) == [] + assert check_unsolvable_diagnostics(context) == [] + + def test_obs4mips_requirement_solves_from_obs4ref_data(self): + provider = _provider_requiring(SourceDatasetType.obs4MIPs, "WECANN-1-0", "gpp") + catalog = _catalog( + [("obs4REF.WECANN-1-0.gpp", "WECANN-1-0", "gpp", "2007-01-01", "2015-12-01", "/d/gpp.nc")] + ) + context = _context({SourceDatasetType.obs4REF: catalog}, [provider]) + + assert check_unsolvable_diagnostics(context) == [] class TestDiagnose: @@ -273,3 +511,30 @@ def test_worst_severity(self, severities, expected): findings = [Finding(severity=s, summary="s") for s in severities] assert worst_severity(findings) == expected + + +def test_diagnose_snapshot_seeded(db_seeded, config, data_regression): + """ + Pin the doctor findings over the seeded catalogs and every in-repo provider. + + This is the doctor half of the oracle for the obs4REF fallback work, + so do not regenerate it with ``--force-regen``. + """ + context = DoctorContext(config=config, database=db_seeded) + context._providers = [example_provider, pmp_provider, esmvaltool_provider, ilamb_provider] + + findings = diagnose(context).findings + + reported = [ + { + "check": finding.check, + "severity": str(finding.severity), + "summary": finding.summary, + "detail": finding.detail, + "remedy": finding.remedy, + "command": finding.command, + } + for finding in findings + ] + + data_regression.check(sorted(reported, key=lambda entry: tuple(sorted(entry.items())))) diff --git a/packages/climate-ref/tests/unit/test_doctor/test_diagnose_snapshot_seeded.yml b/packages/climate-ref/tests/unit/test_doctor/test_diagnose_snapshot_seeded.yml new file mode 100644 index 000000000..224b82152 --- /dev/null +++ b/packages/climate-ref/tests/unit/test_doctor/test_diagnose_snapshot_seeded.yml @@ -0,0 +1,244 @@ +- check: missing-reference-data + command: '' + detail: Needed for areacello, sic by esmvaltool/sea-ice-area-basic. + remedy: No registry carries these and they are not known to be on ESGF. + severity: warning + summary: OSI-450-nh (esmvaltool-reference) is not ingested, so 1 diagnostic will + not run +- check: missing-reference-data + command: '' + detail: Needed for areacello, sic by esmvaltool/sea-ice-area-basic. + remedy: No registry carries these and they are not known to be on ESGF. + severity: warning + summary: OSI-450-sh (esmvaltool-reference) is not ingested, so 1 diagnostic will + not run +- check: missing-reference-data + command: '' + detail: Needed for lai by ilamb/lai-avh15c1. + remedy: These are published to obs4MIPs on ESGF, and `scripts/fetch-esgf.py` has + a request for each. See the 'Download required datasets' guide. + severity: warning + summary: NOAA-NCEI-LAI-AVHRR-5-0 (obs4mips) is not ingested, so 1 diagnostic will + not run +- check: missing-reference-data + command: '' + detail: Needed for psl by pmp/extratropical-modes-of-variability-nam, pmp/extratropical-modes-of-variability-nao, + pmp/extratropical-modes-of-variability-npo, pmp/extratropical-modes-of-variability-pna, + pmp/extratropical-modes-of-variability-sam. + remedy: These are published to obs4MIPs on ESGF, and `scripts/fetch-esgf.py` has + a request for each. See the 'Download required datasets' guide. + severity: warning + summary: 20CR-V2 (obs4mips) is not ingested, so 5 diagnostics will not run +- check: missing-reference-data + command: '' + detail: Needed for rlut, rlutcs, rsut, rsutcs by esmvaltool/cloud-radiative-effects. + remedy: These are published to obs4MIPs on ESGF, and `scripts/fetch-esgf.py` has + a request for each. See the 'Download required datasets' guide. + severity: warning + summary: CERES-EBAF-4-2-1 (obs4mips) is not ingested, so 1 diagnostic will not run +- check: missing-reference-data + command: ref datasets fetch-data --registry obs4ref --output-directory + detail: Needed for burntFractionAll by ilamb/burntfractionall-gfed. + remedy: Fetch these, then ingest the directory they land in. + severity: warning + summary: GFED-5-0 (obs4mips) is not ingested, so 1 diagnostic will not run +- check: missing-reference-data + command: ref datasets fetch-data --registry obs4ref --output-directory + detail: Needed for cSoil by ilamb/csoil-hwsd2. + remedy: Fetch these, then ingest the directory they land in. + severity: warning + summary: HWSD-2-0 (obs4mips) is not ingested, so 1 diagnostic will not run +- check: missing-reference-data + command: ref datasets fetch-data --registry obs4ref --output-directory + detail: Needed for mrro by ilamb/mrro-lora. + remedy: Fetch these, then ingest the directory they land in. + severity: warning + summary: LORA-1-0 (obs4mips) is not ingested, so 1 diagnostic will not run +- check: missing-reference-data + command: ref datasets fetch-data --registry obs4ref --output-directory + detail: Needed for msftmz by ilamb/amoc-rapid. + remedy: Fetch these, then ingest the directory they land in. + severity: warning + summary: RAPID-2023-1a (obs4mips) is not ingested, so 1 diagnostic will not run +- check: missing-reference-data + command: ref datasets fetch-data --registry obs4ref --output-directory + detail: Needed for nbp by ilamb/nbp-hoffman. + remedy: Fetch these, then ingest the directory they land in. + severity: warning + summary: Hoffman-1-0 (obs4mips) is not ingested, so 1 diagnostic will not run +- check: missing-reference-data + command: ref datasets fetch-data --registry obs4ref --output-directory + detail: Needed for snc by ilamb/snc-esacci. + remedy: Fetch these, then ingest the directory they land in. + severity: warning + summary: CCI-CryoClim-FSC-1 (obs4mips) is not ingested, so 1 diagnostic will not + run +- check: missing-reference-data + command: ref datasets fetch-data --registry obs4ref --output-directory + detail: Needed for so, thetao by ilamb/so-woa2023-surface, ilamb/thetao-woa2023-surface. + remedy: Fetch these, then ingest the directory they land in. + severity: warning + summary: WOA-23 (obs4mips) is not ingested, so 2 diagnostics will not run +- check: missing-reference-data + command: ref datasets fetch-data --registry pmp-climatology --output-directory + detail: Needed for pr by pmp/annual-cycle. + remedy: Fetch these, then ingest the directory they land in. + severity: warning + summary: GPCP-3-3 (pmp-climatology) is not ingested, so 1 diagnostic will not run +- check: missing-reference-data + command: ref datasets fetch-data --registry pmp-climatology --output-directory + detail: Needed for psl, ta, ts, ua, uas, va, vas, zg by pmp/annual-cycle. + remedy: Fetch these, then ingest the directory they land in. + severity: warning + summary: ERA-5 (pmp-climatology) is not ingested, so 1 diagnostic will not run +- check: missing-reference-data + command: ref datasets fetch-data --registry pmp-climatology --output-directory + detail: Needed for rlds, rlus, rlut, rsds, rsdt, rsus, rsut by pmp/annual-cycle. + remedy: Fetch these, then ingest the directory they land in. + severity: warning + summary: CERES-EBAF-4-2 (pmp-climatology) is not ingested, so 1 diagnostic will + not run +- check: overlapping-registries + command: '' + detail: 'Carried by: obs4ref, quickstart.' + remedy: Fetch each of these from one registry only. Ingesting two copies of the + same version gives one dataset holding both sets of files. + severity: info + summary: HadISST-1-1 is carried by 2 registries +- check: unsolvable-diagnostics + command: '' + detail: 'Unmet: no cmip6 datasets match experiment_id=historical, table_id=Amon, + variable_id=hurs|pr|tas|tasmax and experiment_id=historical, table_id=Lmon, variable_id=cVeg|treeFrac + and experiment_id=historical, table_id=Emon, variable_id=vegFrac. nothing is ingested + as cmip7.' + remedy: Ingest the data the unmet requirement names, then run the solver again. + severity: warning + summary: esmvaltool/climate-drivers-for-fire has no executions +- check: unsolvable-diagnostics + command: '' + detail: 'Unmet: no cmip6 datasets match experiment_id=historical|land-hist, frequency=mon, + table_id=AERmonZ|Amon|CFmon|Emon|EmonZ|LImon|Lmon|Omon|SImon, variable_id=emp|evspsbl. + nothing is ingested as cmip7.' + remedy: Ingest the data the unmet requirement names, then run the solver again. + severity: warning + summary: ilamb/emp-gleamgpcp2.3 has no executions +- check: unsolvable-diagnostics + command: '' + detail: 'Unmet: no obs4mips datasets match frequency=mon, source_id=CERES-EBAF-4-2-1, + variable_id=rlut|rlutcs|rsut|rsutcs. nothing is ingested as cmip7.' + remedy: Ingest the data the unmet requirement names, then run the solver again. + severity: warning + summary: esmvaltool/cloud-radiative-effects has no executions +- check: unsolvable-diagnostics + command: '' + detail: 'Unmet: no obs4mips datasets match grid_label=gm, source_id=Hoffman-1-0, + variable_id=nbp, version=v20251117. nothing is ingested as cmip7.' + remedy: Ingest the data the unmet requirement names, then run the solver again. + severity: warning + summary: ilamb/nbp-hoffman has no executions +- check: unsolvable-diagnostics + command: '' + detail: 'Unmet: no obs4mips datasets match grid_label=gm, source_id=RAPID-2023-1a, + variable_id=msftmz, version=v20250902. nothing is ingested as cmip7.' + remedy: Ingest the data the unmet requirement names, then run the solver again. + severity: warning + summary: ilamb/amoc-rapid has no executions +- check: unsolvable-diagnostics + command: '' + detail: 'Unmet: no obs4mips datasets match grid_label=gn, source_id=CCI-CryoClim-FSC-1, + variable_id=snc, version=v20250519. nothing is ingested as cmip7.' + remedy: Ingest the data the unmet requirement names, then run the solver again. + severity: warning + summary: ilamb/snc-esacci has no executions +- check: unsolvable-diagnostics + command: '' + detail: 'Unmet: no obs4mips datasets match grid_label=gn, source_id=HWSD-2-0, variable_id=cSoil, + version=v20250903. nothing is ingested as cmip7.' + remedy: Ingest the data the unmet requirement names, then run the solver again. + severity: warning + summary: ilamb/csoil-hwsd2 has no executions +- check: unsolvable-diagnostics + command: '' + detail: 'Unmet: no obs4mips datasets match grid_label=gn, source_id=LORA-1-0, variable_id=mrro, + version=v20250902. nothing is ingested as cmip7.' + remedy: Ingest the data the unmet requirement names, then run the solver again. + severity: warning + summary: ilamb/mrro-lora has no executions +- check: unsolvable-diagnostics + command: '' + detail: 'Unmet: no obs4mips datasets match grid_label=gn, source_id=NOAA-NCEI-LAI-AVHRR-5-0, + variable_id=lai. nothing is ingested as cmip7.' + remedy: Ingest the data the unmet requirement names, then run the solver again. + severity: warning + summary: ilamb/lai-avh15c1 has no executions +- check: unsolvable-diagnostics + command: '' + detail: 'Unmet: no obs4mips datasets match grid_label=gn, source_id=WECANN-1-0, + variable_id=gpp, version=v20250902. nothing is ingested as cmip7.' + remedy: Ingest the data the unmet requirement names, then run the solver again. + severity: warning + summary: ilamb/gpp-wecann has no executions +- check: unsolvable-diagnostics + command: '' + detail: 'Unmet: no obs4mips datasets match grid_label=gn, source_id=WOA-23, variable_id=so, + version=v20251024. nothing is ingested as cmip7.' + remedy: Ingest the data the unmet requirement names, then run the solver again. + severity: warning + summary: ilamb/so-woa2023-surface has no executions +- check: unsolvable-diagnostics + command: '' + detail: 'Unmet: no obs4mips datasets match grid_label=gn, source_id=WOA-23, variable_id=thetao, + version=v20251024. nothing is ingested as cmip7.' + remedy: Ingest the data the unmet requirement names, then run the solver again. + severity: warning + summary: ilamb/thetao-woa2023-surface has no executions +- check: unsolvable-diagnostics + command: '' + detail: 'Unmet: no obs4mips datasets match grid_label=gr, source_id=GFED-5-0, variable_id=burntFractionAll, + version=v20260128. nothing is ingested as cmip7.' + remedy: Ingest the data the unmet requirement names, then run the solver again. + severity: warning + summary: ilamb/burntfractionall-gfed has no executions +- check: unsolvable-diagnostics + command: '' + detail: 'Unmet: no obs4mips datasets match source_id=20CR-V2, variable_id=psl.' + remedy: Ingest the data the unmet requirement names, then run the solver again. + severity: warning + summary: pmp/extratropical-modes-of-variability-nam has no executions +- check: unsolvable-diagnostics + command: '' + detail: 'Unmet: no obs4mips datasets match source_id=20CR-V2, variable_id=psl.' + remedy: Ingest the data the unmet requirement names, then run the solver again. + severity: warning + summary: pmp/extratropical-modes-of-variability-nao has no executions +- check: unsolvable-diagnostics + command: '' + detail: 'Unmet: no obs4mips datasets match source_id=20CR-V2, variable_id=psl.' + remedy: Ingest the data the unmet requirement names, then run the solver again. + severity: warning + summary: pmp/extratropical-modes-of-variability-npo has no executions +- check: unsolvable-diagnostics + command: '' + detail: 'Unmet: no obs4mips datasets match source_id=20CR-V2, variable_id=psl.' + remedy: Ingest the data the unmet requirement names, then run the solver again. + severity: warning + summary: pmp/extratropical-modes-of-variability-pna has no executions +- check: unsolvable-diagnostics + command: '' + detail: 'Unmet: no obs4mips datasets match source_id=20CR-V2, variable_id=psl.' + remedy: Ingest the data the unmet requirement names, then run the solver again. + severity: warning + summary: pmp/extratropical-modes-of-variability-sam has no executions +- check: unsolvable-diagnostics + command: '' + detail: 'Unmet: nothing is ingested as esmvaltool-reference. nothing is ingested + as cmip7.' + remedy: Ingest the data the unmet requirement names, then run the solver again. + severity: warning + summary: esmvaltool/sea-ice-area-basic has no executions +- check: unsolvable-diagnostics + command: '' + detail: 'Unmet: nothing is ingested as pmp-climatology.' + remedy: Ingest the data the unmet requirement names, then run the solver again. + severity: warning + summary: pmp/annual-cycle has no executions diff --git a/packages/climate-ref/tests/unit/test_doctor_registry.py b/packages/climate-ref/tests/unit/test_doctor_registry.py index ffd8e2415..8f37c831c 100644 --- a/packages/climate-ref/tests/unit/test_doctor_registry.py +++ b/packages/climate-ref/tests/unit/test_doctor_registry.py @@ -15,6 +15,9 @@ "missing-reference-data", "unreachable-source-type", "overlapping-registries", + "misfiled-obs4ref", + "superseded-obs4ref", + "unsolvable-diagnostics", } diff --git a/packages/climate-ref/tests/unit/test_solver.py b/packages/climate-ref/tests/unit/test_solver.py index 732765d15..5226420a9 100644 --- a/packages/climate-ref/tests/unit/test_solver.py +++ b/packages/climate-ref/tests/unit/test_solver.py @@ -20,11 +20,15 @@ DiagnosticExecution, ExecutionSolver, SolveFilterOptions, + _solve_from_data_requirements, apply_dataset_filters, + apply_obs4ref_fallback, + catalog_for_requirement, extract_covered_datasets, matches_filter, solve_executions, solve_required_executions, + union_with_fallbacks, ) from climate_ref_core.constraints import AddParentDataset, AddSupplementaryDataset, RequireFacets from climate_ref_core.datasets import SourceDatasetType @@ -787,6 +791,31 @@ def test_two_executions_same_group_distinct_output_fragments( assert fragment_b.split("/")[-1] == str(executions[1].id) +def test_solve_snapshot_all_providers(db_seeded, config, data_regression): + """ + Pin the solved output across every in-repo provider. + + This is the oracle for the obs4REF fallback work. It must not move when the implicit + fold is replaced by declared fallbacks, so do not regenerate it with ``--force-regen``. + + Rows are sorted because a seeded solve does not fix their order between runs. + `TestObs4REFFallback` pins the order the fallback itself produces. + """ + solver = ExecutionSolver.build_from_db(config, db_seeded) + solver.provider_registry = ProviderRegistry( + providers=[example_provider, pmp_provider, esmvaltool_provider, ilamb_provider] + ) + + output = {} + for execution in solver.solve(): + output[execution.execution_slug()] = { + str(source_type): sorted(collection.datasets[collection.slug_column]) + for source_type, collection in execution.datasets.items() + } + + data_regression.check(output) + + def test_solve_metrics(mocker, db_seeded, solver, data_regression, mock_executor): mock_build_solver = mocker.patch.object(ExecutionSolver, "build_from_db") @@ -1284,7 +1313,7 @@ def test_solve_with_new_datasets(obs4mips_data_catalog, mock_diagnostic, provide assert result_2.datasets.hash != result_1.datasets.hash -def test_solve_with_new_areacella(obs4mips_data_catalog, mock_diagnostic, provider): +def test_solve_with_new_areacella(obs4ref_data_catalog, mock_diagnostic, provider): expected_dataset_key = "cmip6_ssp126_ACCESS-ESM1-5_tas__obs4mips_HadISST-1-1_ts" mock_diagnostic.data_requirements = ( DataRequirement( @@ -1315,7 +1344,7 @@ def test_solve_with_new_areacella(obs4mips_data_catalog, mock_diagnostic, provid result_1 = next( solve_executions( { - SourceDatasetType.obs4MIPs: obs4mips_data_catalog, + SourceDatasetType.obs4REF: obs4ref_data_catalog, SourceDatasetType.CMIP6: cmip_data_catalog, }, mock_diagnostic, @@ -1340,7 +1369,7 @@ def test_solve_with_new_areacella(obs4mips_data_catalog, mock_diagnostic, provid result_2 = next( solve_executions( { - SourceDatasetType.obs4MIPs: obs4mips_data_catalog, + SourceDatasetType.obs4REF: obs4ref_data_catalog, SourceDatasetType.CMIP6: cmip_data_catalog, }, mock_diagnostic, @@ -1953,3 +1982,202 @@ def test_drs_and_complete_parsers_produce_same_executions(config, sample_data_di finally: db_complete.close() db_drs.close() + + +class TestObs4REFFallback: + """obs4MIPs requirements are filled from obs4REF, taking the newest version of each dataset.""" + + @staticmethod + def _frame(prefix, source_ids, version="v1", start=0): + return pd.DataFrame( + { + "instance_id": [f"{prefix}.{prefix}.INST.{s}.mon.ts.gn.{version}" for s in source_ids], + "source_id": list(source_ids), + "variable_id": "ts", + }, + index=range(start, start + len(source_ids)), + ) + + def test_missing_datasets_are_added(self): + obs4mips = self._frame("obs4MIPs", ["A"]) + obs4ref = self._frame("obs4REF", ["A", "B"], start=10) + + merged = union_with_fallbacks(obs4mips, [obs4ref], SourceDatasetType.obs4MIPs) + + # A is taken from obs4MIPs only, B comes from obs4REF and keeps its dataset id. + assert merged["source_id"].tolist() == ["A", "B"] + assert merged.index.tolist() == [0, 1] + assert merged["instance_id"].iloc[1].startswith("obs4REF.") + + def test_the_merged_catalog_cannot_reload_away_the_obs4ref_rows(self): + obs4mips = DataCatalog( + database=None, adapter=CMIP6DatasetAdapter(), df=self._frame("obs4MIPs", ["A"]) + ) + obs4ref = DataCatalog.from_frame(self._frame("obs4REF", ["B"])) + + merged = union_with_fallbacks(obs4mips, [obs4ref], SourceDatasetType.obs4MIPs) + + # A reload would go back to the obs4MIPs adapter alone and drop B. + assert isinstance(merged, DataCatalog) + assert merged.adapter is None + assert merged.to_frame()["source_id"].tolist() == ["A", "B"] + + def test_added_rows_group_as_obs4mips(self): + # pmp/enso groups its reference data by activity_id, so a second value splits it in two. + obs4mips = self._frame("obs4MIPs", ["A"]).assign(activity_id="obs4MIPs") + obs4ref = self._frame("obs4REF", ["B"], start=10).assign(activity_id="obs4REF") + + merged = union_with_fallbacks(obs4mips, [obs4ref], SourceDatasetType.obs4MIPs) + + assert merged["activity_id"].tolist() == ["obs4MIPs", "obs4MIPs"] + assert merged["instance_id"].iloc[1].startswith("obs4REF.") + + def test_obs4mips_wins_a_version_tie(self): + obs4mips = self._frame("obs4MIPs", ["A"], version="v1") + obs4ref = self._frame("obs4REF", ["A"], version="v1", start=10) + + assert union_with_fallbacks(obs4mips, [obs4ref], SourceDatasetType.obs4MIPs) is obs4mips + + def test_a_newer_obs4ref_version_replaces_the_obs4mips_copy(self): + # A stale published copy must not force every diagnostic to rerun on the wrong data. + obs4mips = self._frame("obs4MIPs", ["A", "B"], version="v20240101") + obs4ref = self._frame("obs4REF", ["A"], version="v20250101", start=10) + + merged = union_with_fallbacks(obs4mips, [obs4ref], SourceDatasetType.obs4MIPs) + + assert merged["source_id"].tolist() == ["B", "A"] + assert merged["instance_id"].tolist() == [ + "obs4MIPs.obs4MIPs.INST.B.mon.ts.gn.v20240101", + "obs4REF.obs4REF.INST.A.mon.ts.gn.v20250101", + ] + + def test_an_older_obs4ref_version_is_ignored(self): + obs4mips = self._frame("obs4MIPs", ["A"], version="v10") + obs4ref = self._frame("obs4REF", ["A"], version="v9", start=10) + + assert union_with_fallbacks(obs4mips, [obs4ref], SourceDatasetType.obs4MIPs) is obs4mips + + def test_a_primary_without_instance_id_is_left_alone(self): + obs4mips = pd.DataFrame({"source_id": ["A"], "variable_id": "ts"}) + obs4ref = self._frame("obs4REF", ["B"]) + + assert union_with_fallbacks(obs4mips, [obs4ref], SourceDatasetType.obs4MIPs) is obs4mips + + def test_untouched_when_nothing_to_add(self): + obs4mips = self._frame("obs4MIPs", ["A"]) + + assert union_with_fallbacks(obs4mips, [pd.DataFrame()], SourceDatasetType.obs4MIPs) is obs4mips + + def test_obs4ref_alone_still_groups_as_obs4mips(self): + # A deployment that fetched only the registry is the ordinary case, not an edge case. + obs4ref = self._frame("obs4REF", ["A"]).assign(activity_id="obs4REF") + + merged = union_with_fallbacks(pd.DataFrame(), [obs4ref], SourceDatasetType.obs4MIPs) + + assert merged["activity_id"].tolist() == ["obs4MIPs"] + assert merged["instance_id"].tolist() == obs4ref["instance_id"].tolist() + + def test_only_the_obs4mips_catalog_is_extended(self): + catalogs = { + SourceDatasetType.obs4MIPs: self._frame("obs4MIPs", []), + SourceDatasetType.obs4REF: self._frame("obs4REF", ["A"]), + } + + applied = apply_obs4ref_fallback(catalogs) + + assert len(applied[SourceDatasetType.obs4MIPs]) == 1 + assert applied[SourceDatasetType.obs4REF] is catalogs[SourceDatasetType.obs4REF] + + def test_untouched_without_an_obs4ref_catalog(self): + catalogs = {SourceDatasetType.obs4MIPs: self._frame("obs4MIPs", ["A"])} + + assert apply_obs4ref_fallback(catalogs) is catalogs + + +class TestDeclaredFallbacks: + """A requirement names the collections that may stand in for its source type.""" + + # PMPClimatology is never folded globally, so a union of it can only come from the requirement. + FALLBACK = SourceDatasetType.PMPClimatology + + @staticmethod + def _frame(prefix, source_ids, version="v1", start=0): + return pd.DataFrame( + { + "instance_id": [f"{prefix}.{prefix}.INST.{s}.mon.ts.gn.{version}" for s in source_ids], + "source_id": list(source_ids), + "variable_id": "ts", + "activity_id": prefix, + "path": [f"/data/{prefix}/{s}.nc" for s in source_ids], + }, + index=range(start, start + len(source_ids)), + ) + + def _requirement(self, fallbacks): + return DataRequirement( + source_type=SourceDatasetType.obs4MIPs, + filters=(), + group_by=("activity_id",), + fallback_source_types=fallbacks, + ) + + def test_a_declared_fallback_is_unioned_into_the_requirement(self): + catalogs = { + SourceDatasetType.obs4MIPs: self._frame("obs4MIPs", ["A"]), + self.FALLBACK: self._frame("pmp-climatology", ["B"], start=10), + } + + catalog = catalog_for_requirement(catalogs, self._requirement((self.FALLBACK,))) + + assert catalog["source_id"].tolist() == ["A", "B"] + assert catalog["activity_id"].tolist() == ["obs4MIPs", "obs4MIPs"] + assert catalog.index.tolist() == [0, 1] + + def test_an_undeclared_collection_is_left_out(self): + catalogs = { + SourceDatasetType.obs4MIPs: self._frame("obs4MIPs", ["A"]), + self.FALLBACK: self._frame("pmp-climatology", ["B"], start=10), + } + + catalog = catalog_for_requirement(catalogs, self._requirement(())) + + assert catalog["source_id"].tolist() == ["A"] + + def test_a_requirement_solves_from_its_fallback_alone(self, provider, mock_diagnostic): + # An ordinary registry-only deployment ingests nothing under the primary type. + catalogs = {self.FALLBACK: self._frame("pmp-climatology", ["A", "B"])} + + executions = list( + _solve_from_data_requirements( + catalogs, mock_diagnostic, [self._requirement((self.FALLBACK,))], provider + ) + ) + + # The data is delivered under the primary type whichever collection supplied it. + assert len(executions) == 1 + datasets = executions[0].datasets[SourceDatasetType.obs4MIPs] + assert datasets["source_id"].tolist() == ["A", "B"] + assert datasets.selector_dict() == {"activity_id": "obs4MIPs"} + + def test_a_missing_fallback_catalog_is_tolerated(self): + catalogs = {SourceDatasetType.obs4MIPs: self._frame("obs4MIPs", ["A"])} + + catalog = catalog_for_requirement(catalogs, self._requirement((self.FALLBACK,))) + + assert catalog["source_id"].tolist() == ["A"] + + def test_nothing_ingested_under_the_primary_or_any_fallback(self): + assert catalog_for_requirement({}, self._requirement((self.FALLBACK,))) is None + + def test_the_union_is_idempotent(self): + # The global fold and the per-requirement union both run, so applying twice must not double up. + primary = self._frame("obs4MIPs", ["A"]) + fallback = self._frame("obs4REF", ["A", "B"], start=10) + + once = union_with_fallbacks(primary, [fallback], SourceDatasetType.obs4MIPs) + twice = union_with_fallbacks(once, [fallback], SourceDatasetType.obs4MIPs) + + assert twice is once + pd.testing.assert_frame_equal(once, twice) + assert once["source_id"].tolist() == ["A", "B"] + assert once.index.tolist() == [0, 1] diff --git a/packages/climate-ref/tests/unit/test_solver/test_solve_metrics.yml b/packages/climate-ref/tests/unit/test_solver/test_solve_metrics.yml index b867d98a8..a56192887 100644 --- a/packages/climate-ref/tests/unit/test_solver/test_solve_metrics.yml +++ b/packages/climate-ref/tests/unit/test_solver/test_solve_metrics.yml @@ -35,7 +35,7 @@ cmip6_historical_ACCESS-ESM1-5_tos_r1i1p1f1__obs4mips_HadISST-1-1_ts: - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Omon.tos.gn.v20191115 - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Ofx.areacello.gn.v20191115 SourceDatasetType.obs4MIPs: - - obs4MIPs.obs4MIPs.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 + - obs4REF.obs4REF.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 cmip6_historical_CESM2_rsut_r1i1p1f1: SourceDatasetType.CMIP6: - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Amon.rsut.gn.v20190308 diff --git a/packages/climate-ref/tests/unit/test_solver/test_solve_snapshot_all_providers.yml b/packages/climate-ref/tests/unit/test_solver/test_solve_snapshot_all_providers.yml new file mode 100644 index 000000000..2f7dac014 --- /dev/null +++ b/packages/climate-ref/tests/unit/test_solver/test_solve_snapshot_all_providers.yml @@ -0,0 +1,651 @@ +esmvaltool/climate-at-global-warming-levels/cmip6_ssp126: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.pr.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.tas.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.fx.areacella.gn.v20191115 + - CMIP6.ScenarioMIP.CSIRO.ACCESS-ESM1-5.ssp126.r1i1p1f1.Amon.pr.gn.v20210318 + - CMIP6.ScenarioMIP.CSIRO.ACCESS-ESM1-5.ssp126.r1i1p1f1.Amon.tas.gn.v20210318 + - CMIP6.ScenarioMIP.CSIRO.ACCESS-ESM1-5.ssp126.r1i1p1f1.fx.areacella.gn.v20210318 +esmvaltool/cloud-scatterplots-cli-ta/cmip6_historical_mon_gn_r1i1p1f1_CESM2: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Amon.cli.gn.v20190308 + - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Amon.ta.gn.v20190308 + - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.fx.areacella.gn.v20190308 +esmvaltool/cloud-scatterplots-clivi-lwcre/cmip6_historical_mon_gn_r1i1p1f1_CESM2: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Amon.clivi.gn.v20190308 + - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Amon.rlut.gn.v20190308 + - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Amon.rlutcs.gn.v20190308 + - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.fx.areacella.gn.v20190308 +esmvaltool/cloud-scatterplots-clt-swcre/cmip6_historical_mon_gn_r1i1p1f1_CESM2: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Amon.clt.gn.v20190308 + - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Amon.rsut.gn.v20190308 + - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Amon.rsutcs.gn.v20190308 + - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.fx.areacella.gn.v20190308 +esmvaltool/cloud-scatterplots-clwvi-pr/cmip6_historical_mon_gn_r1i1p1f1_CESM2: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Amon.clwvi.gn.v20190308 + - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Amon.pr.gn.v20190401 + - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.fx.areacella.gn.v20190308 +esmvaltool/cloud-scatterplots-reference/obs4mips_obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ta.25km.gn.v20250220: + SourceDatasetType.obs4MIPs: + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ta.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ta.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ta.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ta.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ta.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ta.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ta.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ta.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ta.25km.gn.v20250220 +esmvaltool/enso-basic-climatology/cmip6_gn_r1i1p1f1_ACCESS-ESM1-5: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.pr.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.tauu.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Omon.tos.gn.v20191115 +esmvaltool/enso-characteristics/cmip6_gn_r1i1p1f1_ACCESS-ESM1-5: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Ofx.areacello.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Omon.tos.gn.v20191115 +esmvaltool/equilibrium-climate-sensitivity/cmip6_gn_r1i1p1f1_ACCESS-ESM1-5: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.abrupt-4xCO2.r1i1p1f1.Amon.rlut.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.abrupt-4xCO2.r1i1p1f1.Amon.rsdt.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.abrupt-4xCO2.r1i1p1f1.Amon.rsut.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.abrupt-4xCO2.r1i1p1f1.Amon.tas.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.abrupt-4xCO2.r1i1p1f1.fx.areacella.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.piControl.r1i1p1f1.Amon.rlut.gn.v20210316 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.piControl.r1i1p1f1.Amon.rsdt.gn.v20210316 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.piControl.r1i1p1f1.Amon.rsut.gn.v20210316 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.piControl.r1i1p1f1.Amon.tas.gn.v20210316 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.piControl.r1i1p1f1.fx.areacella.gn.v20210316 +esmvaltool/global-mean-timeseries/cmip6_1pctCO2_gn_r1i1p1f1_ACCESS-ESM1-5_Amon_tas: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.1pctCO2.r1i1p1f1.Amon.tas.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.1pctCO2.r1i1p1f1.fx.areacella.gn.v20191115 +esmvaltool/global-mean-timeseries/cmip6_abrupt-4xCO2_gn_r1i1p1f1_ACCESS-ESM1-5_Amon_tas: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.abrupt-4xCO2.r1i1p1f1.Amon.tas.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.abrupt-4xCO2.r1i1p1f1.fx.areacella.gn.v20191115 +esmvaltool/global-mean-timeseries/cmip6_esm-1pct-brch-1000PgC_gn_r1i1p1f1_ACCESS-ESM1-5_Amon_tas: + SourceDatasetType.CMIP6: + - CMIP6.C4MIP CDRMIP.CSIRO.ACCESS-ESM1-5.esm-1pct-brch-1000PgC.r1i1p1f1.Amon.tas.gn.v20191206 + - CMIP6.C4MIP CDRMIP.CSIRO.ACCESS-ESM1-5.esm-1pct-brch-1000PgC.r1i1p1f1.fx.areacella.gn.v20191206 +esmvaltool/global-mean-timeseries/cmip6_esm-1pctCO2_gn_r1i1p1f1_MPI-ESM1-2-LR_Amon_tas: + SourceDatasetType.CMIP6: + - CMIP6.C4MIP CDRMIP.MPI-M.MPI-ESM1-2-LR.esm-1pctCO2.r1i1p1f1.Amon.tas.gn.v20190815 + - CMIP6.C4MIP CDRMIP.MPI-M.MPI-ESM1-2-LR.esm-1pctCO2.r1i1p1f1.Amon.tas.gn.v20190815 + - CMIP6.C4MIP CDRMIP.MPI-M.MPI-ESM1-2-LR.esm-1pctCO2.r1i1p1f1.Amon.tas.gn.v20190815 + - CMIP6.C4MIP CDRMIP.MPI-M.MPI-ESM1-2-LR.esm-1pctCO2.r1i1p1f1.Amon.tas.gn.v20190815 + - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.esm-piControl.r1i1p1f1.fx.areacella.gn.v20190815 +esmvaltool/global-mean-timeseries/cmip6_esm-piControl_gn_r1i1p1f1_MPI-ESM1-2-LR_Amon_tas: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.esm-piControl.r1i1p1f1.Amon.tas.gn.v20190815 + - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.esm-piControl.r1i1p1f1.Amon.tas.gn.v20190815 + - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.esm-piControl.r1i1p1f1.Amon.tas.gn.v20190815 + - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.esm-piControl.r1i1p1f1.Amon.tas.gn.v20190815 + - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.esm-piControl.r1i1p1f1.fx.areacella.gn.v20190815 +esmvaltool/global-mean-timeseries/cmip6_historical_gn_r1i1p1f1_ACCESS-ESM1-5_Amon_tas: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.tas.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.fx.areacella.gn.v20191115 +esmvaltool/global-mean-timeseries/cmip6_historical_gn_r1i1p1f1_CanESM5_Amon_tas: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.Amon.tas.gn.v20190429 + - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.fx.areacella.gn.v20190429 +esmvaltool/global-mean-timeseries/cmip6_historical_gn_r1i1p1f3_HadGEM3-GC31-LL_Amon_tas: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.MOHC.HadGEM3-GC31-LL.historical.r1i1p1f3.Amon.tas.gn.v20190624 + - CMIP6.CMIP.MOHC.HadGEM3-GC31-LL.piControl.r1i1p1f1.fx.areacella.gn.v20190709 +esmvaltool/global-mean-timeseries/cmip6_piControl_gn_r1i1p1f1_ACCESS-ESM1-5_Amon_tas: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.piControl.r1i1p1f1.Amon.tas.gn.v20210316 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.piControl.r1i1p1f1.fx.areacella.gn.v20210316 +esmvaltool/global-mean-timeseries/cmip6_ssp126_gn_r1i1p1f1_ACCESS-ESM1-5_Amon_tas: + SourceDatasetType.CMIP6: + - CMIP6.ScenarioMIP.CSIRO.ACCESS-ESM1-5.ssp126.r1i1p1f1.Amon.tas.gn.v20210318 + - CMIP6.ScenarioMIP.CSIRO.ACCESS-ESM1-5.ssp126.r1i1p1f1.fx.areacella.gn.v20210318 +esmvaltool/ozone-annual-cycle/cmip6_gr_r1i1p1f2_CNRM-ESM2-1__obs4mips_C3S-GTO-ECV-9-0: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.AERmon.toz.gr.v20181206 + SourceDatasetType.obs4MIPs: + - obs4MIPs.obs4MIPs.DLR-BIRA.C3S-GTO-ECV-9-0.mon.toz.1x1degree.gn.v20231115 +esmvaltool/ozone-lat-time/cmip6_gr_r1i1p1f2_CNRM-ESM2-1__obs4mips_C3S-GTO-ECV-9-0: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.AERmon.toz.gr.v20181206 + SourceDatasetType.obs4MIPs: + - obs4MIPs.obs4MIPs.DLR-BIRA.C3S-GTO-ECV-9-0.mon.toz.1x1degree.gn.v20231115 +esmvaltool/ozone-nh-mar/cmip6_gr_r1i1p1f2_CNRM-ESM2-1__obs4mips_C3S-GTO-ECV-9-0: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.AERmon.toz.gr.v20181206 + SourceDatasetType.obs4MIPs: + - obs4MIPs.obs4MIPs.DLR-BIRA.C3S-GTO-ECV-9-0.mon.toz.1x1degree.gn.v20231115 +esmvaltool/ozone-sh-oct/cmip6_gr_r1i1p1f2_CNRM-ESM2-1__obs4mips_C3S-GTO-ECV-9-0: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.AERmon.toz.gr.v20181206 + SourceDatasetType.obs4MIPs: + - obs4MIPs.obs4MIPs.DLR-BIRA.C3S-GTO-ECV-9-0.mon.toz.1x1degree.gn.v20231115 +esmvaltool/ozone-zonal/cmip6_gr_r1i1p1f2_CNRM-ESM2-1: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CNRM-CERFACS.CNRM-ESM2-1.historical.r1i1p1f2.Amon.o3.gr.v20181206 +esmvaltool/regional-historical-annual-cycle/cmip6_gn_r1i1p1f1_ACCESS-ESM1-5: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.hus.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.pr.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.psl.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.tas.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.ua.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.fx.areacella.gn.v20191115 +esmvaltool/regional-historical-annual-cycle/cmip6_gn_r1i1p1f1_CanESM5: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.Amon.tas.gn.v20190429 + - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.fx.areacella.gn.v20190429 +esmvaltool/regional-historical-annual-cycle/cmip6_gn_r1i1p1f3_HadGEM3-GC31-LL: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.MOHC.HadGEM3-GC31-LL.historical.r1i1p1f3.Amon.tas.gn.v20190624 + - CMIP6.CMIP.MOHC.HadGEM3-GC31-LL.piControl.r1i1p1f1.fx.areacella.gn.v20190709 +esmvaltool/regional-historical-annual-cycle/obs4mips_ERA-5: + SourceDatasetType.obs4MIPs: + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 +esmvaltool/regional-historical-timeseries/cmip6_gn_r1i1p1f1_ACCESS-ESM1-5: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.hus.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.pr.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.psl.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.tas.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.ua.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.fx.areacella.gn.v20191115 +esmvaltool/regional-historical-timeseries/cmip6_gn_r1i1p1f1_CanESM5: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.Amon.tas.gn.v20190429 + - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.fx.areacella.gn.v20190429 +esmvaltool/regional-historical-timeseries/cmip6_gn_r1i1p1f3_HadGEM3-GC31-LL: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.MOHC.HadGEM3-GC31-LL.historical.r1i1p1f3.Amon.tas.gn.v20190624 + - CMIP6.CMIP.MOHC.HadGEM3-GC31-LL.piControl.r1i1p1f1.fx.areacella.gn.v20190709 +esmvaltool/regional-historical-timeseries/obs4mips_ERA-5: + SourceDatasetType.obs4MIPs: + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 +esmvaltool/regional-historical-trend/cmip6_gn_r1i1p1f1_ACCESS-ESM1-5: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.hus.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.pr.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.psl.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.tas.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.ua.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.fx.areacella.gn.v20191115 +esmvaltool/regional-historical-trend/cmip6_gn_r1i1p1f1_CanESM5: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.Amon.tas.gn.v20190429 + - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.fx.areacella.gn.v20190429 +esmvaltool/regional-historical-trend/cmip6_gn_r1i1p1f3_HadGEM3-GC31-LL: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.MOHC.HadGEM3-GC31-LL.historical.r1i1p1f3.Amon.tas.gn.v20190624 + - CMIP6.CMIP.MOHC.HadGEM3-GC31-LL.piControl.r1i1p1f1.fx.areacella.gn.v20190709 +esmvaltool/regional-historical-trend/obs4mips_ERA-5: + SourceDatasetType.obs4MIPs: + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.psl.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.tas.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 + - obs4MIPs.obs4MIPs.ECMWF.ERA-5.mon.ua.25km.gn.v20250220 +esmvaltool/sea-ice-sensitivity/cmip6_historical: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.Amon.tas.gn.v20190429 + - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.Ofx.areacello.gn.v20190429 + - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.SImon.siconc.gn.v20190429 + - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.fx.areacella.gn.v20190429 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.tas.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Ofx.areacello.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.SImon.siconc.gn.v20200817 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.fx.areacella.gn.v20191115 + - CMIP6.CMIP.MOHC.HadGEM3-GC31-LL.historical.r1i1p1f3.Amon.tas.gn.v20190624 + - CMIP6.CMIP.MOHC.HadGEM3-GC31-LL.historical.r1i1p1f3.SImon.siconc.gn.v20200330 + - CMIP6.CMIP.MOHC.HadGEM3-GC31-LL.piControl.r1i1p1f1.Ofx.areacello.gn.v20190709 + - CMIP6.CMIP.MOHC.HadGEM3-GC31-LL.piControl.r1i1p1f1.fx.areacella.gn.v20190709 +esmvaltool/transient-climate-response-emissions/cmip6_gn_r1i1p1f1_MPI-ESM1-2-LR: + SourceDatasetType.CMIP6: + - CMIP6.C4MIP CDRMIP.MPI-M.MPI-ESM1-2-LR.esm-1pctCO2.r1i1p1f1.Amon.fco2antt.gn.v20190815 + - CMIP6.C4MIP CDRMIP.MPI-M.MPI-ESM1-2-LR.esm-1pctCO2.r1i1p1f1.Amon.fco2antt.gn.v20190815 + - CMIP6.C4MIP CDRMIP.MPI-M.MPI-ESM1-2-LR.esm-1pctCO2.r1i1p1f1.Amon.fco2antt.gn.v20190815 + - CMIP6.C4MIP CDRMIP.MPI-M.MPI-ESM1-2-LR.esm-1pctCO2.r1i1p1f1.Amon.fco2antt.gn.v20190815 + - CMIP6.C4MIP CDRMIP.MPI-M.MPI-ESM1-2-LR.esm-1pctCO2.r1i1p1f1.Amon.tas.gn.v20190815 + - CMIP6.C4MIP CDRMIP.MPI-M.MPI-ESM1-2-LR.esm-1pctCO2.r1i1p1f1.Amon.tas.gn.v20190815 + - CMIP6.C4MIP CDRMIP.MPI-M.MPI-ESM1-2-LR.esm-1pctCO2.r1i1p1f1.Amon.tas.gn.v20190815 + - CMIP6.C4MIP CDRMIP.MPI-M.MPI-ESM1-2-LR.esm-1pctCO2.r1i1p1f1.Amon.tas.gn.v20190815 + - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.esm-piControl.r1i1p1f1.Amon.tas.gn.v20190815 + - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.esm-piControl.r1i1p1f1.Amon.tas.gn.v20190815 + - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.esm-piControl.r1i1p1f1.Amon.tas.gn.v20190815 + - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.esm-piControl.r1i1p1f1.Amon.tas.gn.v20190815 + - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.esm-piControl.r1i1p1f1.fx.areacella.gn.v20190815 +esmvaltool/transient-climate-response/cmip6_gn_r1i1p1f1_ACCESS-ESM1-5: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.1pctCO2.r1i1p1f1.Amon.tas.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.1pctCO2.r1i1p1f1.fx.areacella.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.piControl.r1i1p1f1.Amon.tas.gn.v20210316 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.piControl.r1i1p1f1.fx.areacella.gn.v20210316 +esmvaltool/zero-emission-commitment/cmip6_gn_r1i1p1f1_ACCESS-ESM1-5: + SourceDatasetType.CMIP6: + - CMIP6.C4MIP CDRMIP.CSIRO.ACCESS-ESM1-5.esm-1pct-brch-1000PgC.r1i1p1f1.Amon.tas.gn.v20191206 + - CMIP6.C4MIP CDRMIP.CSIRO.ACCESS-ESM1-5.esm-1pct-brch-1000PgC.r1i1p1f1.fx.areacella.gn.v20191206 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.1pctCO2.r1i1p1f1.Amon.tas.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.1pctCO2.r1i1p1f1.fx.areacella.gn.v20191115 +example/global-mean-timeseries/cmip6_1pctCO2_ACCESS-ESM1-5_tas_r1i1p1f1: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.1pctCO2.r1i1p1f1.Amon.tas.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.1pctCO2.r1i1p1f1.fx.areacella.gn.v20191115 +example/global-mean-timeseries/cmip6_abrupt-4xCO2_ACCESS-ESM1-5_rsut_r1i1p1f1: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.abrupt-4xCO2.r1i1p1f1.Amon.rsut.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.abrupt-4xCO2.r1i1p1f1.fx.areacella.gn.v20191115 +example/global-mean-timeseries/cmip6_abrupt-4xCO2_ACCESS-ESM1-5_tas_r1i1p1f1: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.abrupt-4xCO2.r1i1p1f1.Amon.tas.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.abrupt-4xCO2.r1i1p1f1.fx.areacella.gn.v20191115 +example/global-mean-timeseries/cmip6_esm-1pct-brch-1000PgC_ACCESS-ESM1-5_tas_r1i1p1f1: + SourceDatasetType.CMIP6: + - CMIP6.C4MIP CDRMIP.CSIRO.ACCESS-ESM1-5.esm-1pct-brch-1000PgC.r1i1p1f1.Amon.tas.gn.v20191206 + - CMIP6.C4MIP CDRMIP.CSIRO.ACCESS-ESM1-5.esm-1pct-brch-1000PgC.r1i1p1f1.fx.areacella.gn.v20191206 +example/global-mean-timeseries/cmip6_esm-1pctCO2_MPI-ESM1-2-LR_tas_r1i1p1f1: + SourceDatasetType.CMIP6: + - CMIP6.C4MIP CDRMIP.MPI-M.MPI-ESM1-2-LR.esm-1pctCO2.r1i1p1f1.Amon.tas.gn.v20190815 + - CMIP6.C4MIP CDRMIP.MPI-M.MPI-ESM1-2-LR.esm-1pctCO2.r1i1p1f1.Amon.tas.gn.v20190815 + - CMIP6.C4MIP CDRMIP.MPI-M.MPI-ESM1-2-LR.esm-1pctCO2.r1i1p1f1.Amon.tas.gn.v20190815 + - CMIP6.C4MIP CDRMIP.MPI-M.MPI-ESM1-2-LR.esm-1pctCO2.r1i1p1f1.Amon.tas.gn.v20190815 + - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.esm-piControl.r1i1p1f1.fx.areacella.gn.v20190815 +example/global-mean-timeseries/cmip6_esm-piControl_MPI-ESM1-2-LR_tas_r1i1p1f1: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.esm-piControl.r1i1p1f1.Amon.tas.gn.v20190815 + - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.esm-piControl.r1i1p1f1.Amon.tas.gn.v20190815 + - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.esm-piControl.r1i1p1f1.Amon.tas.gn.v20190815 + - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.esm-piControl.r1i1p1f1.Amon.tas.gn.v20190815 + - CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.esm-piControl.r1i1p1f1.fx.areacella.gn.v20190815 +example/global-mean-timeseries/cmip6_historical_ACCESS-ESM1-5_rsut_r1i1p1f1: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.rsut.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.fx.areacella.gn.v20191115 +example/global-mean-timeseries/cmip6_historical_ACCESS-ESM1-5_tas_r1i1p1f1: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.tas.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.fx.areacella.gn.v20191115 +example/global-mean-timeseries/cmip6_historical_CESM2_rsut_r1i1p1f1: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Amon.rsut.gn.v20190308 + - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.fx.areacella.gn.v20190308 +example/global-mean-timeseries/cmip6_historical_CanESM5_tas_r1i1p1f1: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.Amon.tas.gn.v20190429 + - CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.fx.areacella.gn.v20190429 +example/global-mean-timeseries/cmip6_historical_HadGEM3-GC31-LL_tas_r1i1p1f3: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.MOHC.HadGEM3-GC31-LL.historical.r1i1p1f3.Amon.tas.gn.v20190624 + - CMIP6.CMIP.MOHC.HadGEM3-GC31-LL.piControl.r1i1p1f1.fx.areacella.gn.v20190709 +example/global-mean-timeseries/cmip6_piControl_ACCESS-ESM1-5_rsut_r1i1p1f1: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.piControl.r1i1p1f1.Amon.rsut.gn.v20210316 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.piControl.r1i1p1f1.fx.areacella.gn.v20210316 +example/global-mean-timeseries/cmip6_piControl_ACCESS-ESM1-5_tas_r1i1p1f1: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.piControl.r1i1p1f1.Amon.tas.gn.v20210316 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.piControl.r1i1p1f1.fx.areacella.gn.v20210316 +example/global-mean-timeseries/cmip6_ssp126_ACCESS-ESM1-5_rsut_r1i1p1f1: + SourceDatasetType.CMIP6: + - CMIP6.ScenarioMIP.CSIRO.ACCESS-ESM1-5.ssp126.r1i1p1f1.Amon.rsut.gn.v20210318 + - CMIP6.ScenarioMIP.CSIRO.ACCESS-ESM1-5.ssp126.r1i1p1f1.fx.areacella.gn.v20210318 +example/global-mean-timeseries/cmip6_ssp126_ACCESS-ESM1-5_tas_r1i1p1f1: + SourceDatasetType.CMIP6: + - CMIP6.ScenarioMIP.CSIRO.ACCESS-ESM1-5.ssp126.r1i1p1f1.Amon.tas.gn.v20210318 + - CMIP6.ScenarioMIP.CSIRO.ACCESS-ESM1-5.ssp126.r1i1p1f1.fx.areacella.gn.v20210318 +example/global-sst-bias/cmip6_historical_ACCESS-ESM1-5_tos_r1i1p1f1__obs4mips_HadISST-1-1_ts: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Ofx.areacello.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Omon.tos.gn.v20191115 + SourceDatasetType.obs4MIPs: + - obs4REF.obs4REF.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 +ilamb/gpp-fluxnet2015/cmip6_historical_gn_r1i1p1f1_ACCESS-ESM1-5: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Lmon.gpp.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.fx.areacella.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.fx.sftlf.gn.v20191115 +ilamb/mrsos-wangmao/cmip6_historical_gn_r1i1p1f1_ACCESS-ESM1-5: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Lmon.mrsos.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.fx.areacella.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.fx.sftlf.gn.v20191115 +pmp/enso_proc/cmip6_historical_gn_r1i1p1f1_ACCESS-ESM1-5__obs4mips_obs4MIPs: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.tauu.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.ts.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.fx.areacella.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.fx.sftlf.gn.v20191115 + SourceDatasetType.obs4MIPs: + - obs4REF.obs4REF.ESSO.TropFlux-1-0.mon.hfls.250km.gn.v20250415 + - obs4REF.obs4REF.ESSO.TropFlux-1-0.mon.hfss.250km.gn.v20250415 + - obs4REF.obs4REF.ESSO.TropFlux-1-0.mon.tauu.250km.gn.v20250415 + - obs4REF.obs4REF.ESSO.TropFlux-1-0.mon.ts.250km.gn.v20210727 + - obs4REF.obs4REF.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 + - obs4REF.obs4REF.NASA-LaRC.CERES-EBAF-4-2.mon.rlds.100km.gn.v20230209 + - obs4REF.obs4REF.NASA-LaRC.CERES-EBAF-4-2.mon.rlus.100km.gn.v20230209 + - obs4REF.obs4REF.NASA-LaRC.CERES-EBAF-4-2.mon.rsds.100km.gn.v20230209 + - obs4REF.obs4REF.NASA-LaRC.CERES-EBAF-4-2.mon.rsus.100km.gn.v20230209 +pmp/enso_proc/cmip6_historical_gn_r2i1p1f1_ACCESS-ESM1-5__obs4mips_obs4MIPs: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.fx.sftlf.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r2i1p1f1.Amon.ts.gn.v20191128 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r2i1p1f1.fx.areacella.gn.v20191128 + SourceDatasetType.obs4MIPs: + - obs4REF.obs4REF.ESSO.TropFlux-1-0.mon.hfls.250km.gn.v20250415 + - obs4REF.obs4REF.ESSO.TropFlux-1-0.mon.hfss.250km.gn.v20250415 + - obs4REF.obs4REF.ESSO.TropFlux-1-0.mon.tauu.250km.gn.v20250415 + - obs4REF.obs4REF.ESSO.TropFlux-1-0.mon.ts.250km.gn.v20210727 + - obs4REF.obs4REF.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 + - obs4REF.obs4REF.NASA-LaRC.CERES-EBAF-4-2.mon.rlds.100km.gn.v20230209 + - obs4REF.obs4REF.NASA-LaRC.CERES-EBAF-4-2.mon.rlus.100km.gn.v20230209 + - obs4REF.obs4REF.NASA-LaRC.CERES-EBAF-4-2.mon.rsds.100km.gn.v20230209 + - obs4REF.obs4REF.NASA-LaRC.CERES-EBAF-4-2.mon.rsus.100km.gn.v20230209 +pmp/enso_tel/cmip6_historical_gn_r1i1p1f1_ACCESS-ESM1-5__obs4mips_obs4MIPs: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.pr.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.ts.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.fx.areacella.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.fx.sftlf.gn.v20191115 + SourceDatasetType.obs4MIPs: + - obs4REF.obs4REF.ESSO.TropFlux-1-0.mon.ts.250km.gn.v20210727 + - obs4REF.obs4REF.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 + - obs4REF.obs4REF.NASA-GSFC.GPCP-Monthly-3-2.mon.pr.50km.gn.v20231205 +pmp/enso_tel/cmip6_historical_gn_r1i1p1f1_CESM2__obs4mips_obs4MIPs: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Amon.pr.gn.v20190401 + - CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.fx.areacella.gn.v20190308 + SourceDatasetType.obs4MIPs: + - obs4REF.obs4REF.ESSO.TropFlux-1-0.mon.ts.250km.gn.v20210727 + - obs4REF.obs4REF.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 + - obs4REF.obs4REF.NASA-GSFC.GPCP-Monthly-3-2.mon.pr.50km.gn.v20231205 +pmp/enso_tel/cmip6_historical_gn_r2i1p1f1_ACCESS-ESM1-5__obs4mips_obs4MIPs: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.fx.sftlf.gn.v20191115 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r2i1p1f1.Amon.ts.gn.v20191128 + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r2i1p1f1.fx.areacella.gn.v20191128 + SourceDatasetType.obs4MIPs: + - obs4REF.obs4REF.ESSO.TropFlux-1-0.mon.ts.250km.gn.v20210727 + - obs4REF.obs4REF.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 + - obs4REF.obs4REF.NASA-GSFC.GPCP-Monthly-3-2.mon.pr.50km.gn.v20231205 +pmp/extratropical-modes-of-variability-npgo/cmip6_hist-GHG_gn_r1i1p1f1_ACCESS-ESM1-5__obs4mips_HadISST-1-1_ts: + SourceDatasetType.CMIP6: + - CMIP6.DAMIP.CSIRO.ACCESS-ESM1-5.hist-GHG.r1i1p1f1.Amon.ts.gn.v20200615 + SourceDatasetType.obs4MIPs: + - obs4REF.obs4REF.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 +pmp/extratropical-modes-of-variability-npgo/cmip6_hist-GHG_gn_r2i1p1f1_ACCESS-ESM1-5__obs4mips_HadISST-1-1_ts: + SourceDatasetType.CMIP6: + - CMIP6.DAMIP.CSIRO.ACCESS-ESM1-5.hist-GHG.r2i1p1f1.Amon.ts.gn.v20200615 + SourceDatasetType.obs4MIPs: + - obs4REF.obs4REF.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 +pmp/extratropical-modes-of-variability-npgo/cmip6_historical_gn_r1i1p1f1_ACCESS-ESM1-5__obs4mips_HadISST-1-1_ts: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.ts.gn.v20191115 + SourceDatasetType.obs4MIPs: + - obs4REF.obs4REF.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 +pmp/extratropical-modes-of-variability-npgo/cmip6_historical_gn_r2i1p1f1_ACCESS-ESM1-5__obs4mips_HadISST-1-1_ts: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r2i1p1f1.Amon.ts.gn.v20191128 + SourceDatasetType.obs4MIPs: + - obs4REF.obs4REF.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 +pmp/extratropical-modes-of-variability-pdo/cmip6_hist-GHG_gn_r1i1p1f1_ACCESS-ESM1-5__obs4mips_HadISST-1-1_ts: + SourceDatasetType.CMIP6: + - CMIP6.DAMIP.CSIRO.ACCESS-ESM1-5.hist-GHG.r1i1p1f1.Amon.ts.gn.v20200615 + SourceDatasetType.obs4MIPs: + - obs4REF.obs4REF.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 +pmp/extratropical-modes-of-variability-pdo/cmip6_hist-GHG_gn_r2i1p1f1_ACCESS-ESM1-5__obs4mips_HadISST-1-1_ts: + SourceDatasetType.CMIP6: + - CMIP6.DAMIP.CSIRO.ACCESS-ESM1-5.hist-GHG.r2i1p1f1.Amon.ts.gn.v20200615 + SourceDatasetType.obs4MIPs: + - obs4REF.obs4REF.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 +pmp/extratropical-modes-of-variability-pdo/cmip6_historical_gn_r1i1p1f1_ACCESS-ESM1-5__obs4mips_HadISST-1-1_ts: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.ts.gn.v20191115 + SourceDatasetType.obs4MIPs: + - obs4REF.obs4REF.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 +pmp/extratropical-modes-of-variability-pdo/cmip6_historical_gn_r2i1p1f1_ACCESS-ESM1-5__obs4mips_HadISST-1-1_ts: + SourceDatasetType.CMIP6: + - CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r2i1p1f1.Amon.ts.gn.v20191128 + SourceDatasetType.obs4MIPs: + - obs4REF.obs4REF.MOHC.HadISST-1-1.mon.ts.250km.gn.v20250415 diff --git a/pyproject.toml b/pyproject.toml index 242d07e62..aba4f1538 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,7 @@ dev = [ "pytest-mock >= 3.12", "pytest-regressions>=2.5.0", "coverage>=7.2.0", - "mypy>=1.20.1", + "mypy>=2.3.1", "ruff>=0.15.11", "pre-commit>=3.3.1", "towncrier>=25.8.0", diff --git a/scripts/ci/mint_diff.py b/scripts/ci/mint_diff.py deleted file mode 100755 index e68cf431f..000000000 --- a/scripts/ci/mint_diff.py +++ /dev/null @@ -1,495 +0,0 @@ -#!/usr/bin/env python -""" -Render a human-readable diff of the regression baselines changed on a branch. - -A mint rewrites each test case's ``manifest.json`` and uploads the curated native outputs to the -content-addressed object store. -The manifest diff therefore names every native file that changed, and both the old and the new blob -remain fetchable by digest, so the change can be reviewed without checking anything out locally. - -Text outputs (JSON, CSV, YAML, HTML) are fetched from the store and rendered as a unified diff. -Binary outputs (NetCDF, PNG) are reported by size delta and linked, because a byte diff would be noise. - -Usage: - uv run python scripts/ci/mint_diff.py [--base origin/main] [--output summary.md] - - --base git ref to compare against. Defaults to origin/${GITHUB_BASE_REF:-main}. - --output write the full, uncapped report here as well as to stdout. - --comment-output write a copy capped to GitHub's comment size limit here. - --store-url base URL of the native store. Defaults to $REF_NATIVE_STORE_URL. - --no-fetch skip all network access and report size deltas only. - -Exits 0 whether or not anything changed. This reports, it does not gate. -""" - -import argparse -import difflib -import json -import os -import sys -import urllib.error -import urllib.request -from dataclasses import dataclass, field -from pathlib import Path - -from git import GitCommandError, Repo - -from climate_ref_core.regression.manifest import Manifest, NativeEntry - -DEFAULT_STORE_URL = "https://baselines.climate-ref.org" - -# Cloudflare serves a 403 to the stdlib default agent, so identify the script instead. -USER_AGENT = "climate-ref-mint-diff" - -# A manifest path needs a diagnostic and test-case directory before a label can be built from it. -_MIN_LABEL_PARTS = 3 - -# Extensions whose blobs are worth fetching and diffing line by line. -TEXT_SUFFIXES = frozenset({".json", ".csv", ".yml", ".yaml", ".html", ".txt", ".md", ".log"}) - -# A blob larger than this is summarised rather than diffed. Keeps a runaway HTML report -# from stalling the job on the download alone. -MAX_FETCH_BYTES = 2_000_000 - -# Unified-diff lines kept per file before the rest is elided. -MAX_DIFF_LINES = 200 - -# Binary rows listed per case before the rest is elided. A large ILAMB or PMP case emits -# hundreds of plots, and the per-file size delta stops being informative long before then. -MAX_BINARY_ROWS = 30 - -# GitHub rejects a comment body over 65536 bytes, so leave headroom for the truncation notice. -MAX_COMMENT_BYTES = 60_000 - - -def open_repo() -> Repo: - """Return the repository containing the current directory.""" - return Repo(Path.cwd(), search_parent_directories=True) - - -def changed_manifests(repo: Repo, base: str) -> list[str]: - """ - Return the repo-relative paths of every test-case manifest that differs from ``base``. - - Uses the merge-base (``base...HEAD``) so commits landing on the base branch after the - feature branch forked are not misreported as baseline changes. - """ - pathspec = ":(glob)packages/**/test-data/**/manifest.json" - try: - out = repo.git.diff("--name-only", f"{base}...HEAD", "--", pathspec) - except GitCommandError: - # A shallow clone may have no merge-base with the base ref. A two-dot diff over-reports - # (it also shows base-branch commits), which is the safe direction for a report. - out = repo.git.diff("--name-only", base, "HEAD", "--", pathspec) - return sorted(line for line in out.splitlines() if line.strip()) - - -def load_at_ref(repo: Repo, ref: str, rel_path: str) -> Manifest | None: - """Load a manifest as it exists at ``ref``, or ``None`` when absent there.""" - try: - text = repo.git.show(f"{ref}:{rel_path}") - except GitCommandError: - return None - return Manifest.loads(text, source=f"{ref}:{rel_path}") - - -def case_label(rel_path: str) -> str: - """ - Derive a ``provider/diagnostic/test-case`` label from a manifest path. - - ``packages/climate-ref-pmp/tests/test-data/annual-cycle/cmip6-ts/manifest.json`` - becomes ``pmp/annual-cycle/cmip6-ts``. - """ - parts = Path(rel_path).parts - provider = parts[1].removeprefix("climate-ref-") if len(parts) > 1 else "?" - tail = parts[-3:-1] if len(parts) >= _MIN_LABEL_PARTS else () - return "/".join((provider, *tail)) - - -@dataclass -class FileChange: - """One native output file that was added, removed, or changed by the mint.""" - - name: str - old: NativeEntry | None - new: NativeEntry | None - diff: str | None = None - note: str | None = None - - @property - def status(self) -> str: - """``added``, ``removed`` or ``changed``.""" - if self.old is None: - return "added" - if self.new is None: - return "removed" - return "changed" - - @property - def is_text(self) -> bool: - """Whether this file's contents are worth diffing line by line.""" - return Path(self.name).suffix.lower() in TEXT_SUFFIXES - - -@dataclass -class CaseDiff: - """Everything that changed for a single test case.""" - - label: str - rel_path: str - base: Manifest | None - head: Manifest | None - native: list[FileChange] = field(default_factory=list) - committed: list[str] = field(default_factory=list) - metadata: list[str] = field(default_factory=list) - - @property - def is_new(self) -> bool: - """Whether the whole test case is new on this branch.""" - return self.base is None - - @property - def is_removed(self) -> bool: - """Whether the whole test case was deleted on this branch.""" - return self.head is None - - -def _metadata_changes(base: Manifest | None, head: Manifest | None) -> list[str]: - """Describe the scalar manifest fields that moved.""" - if head is None: - return ["test case removed"] - if base is None: - return [f"new test case at `test_case_version` {head.test_case_version}"] - changes = [] - for name in ("test_case_version", "diagnostic_version", "catalog_hash", "schema"): - old, new = getattr(base, name), getattr(head, name) - if old != new: - changes.append(f"`{name}`: `{old}` -> `{new}`") - return changes - - -def _committed_changes(base: Manifest | None, head: Manifest | None) -> list[str]: - """Name the committed regression artefacts whose digest moved.""" - old = base.committed if base else {} - new = head.committed if head else {} - names = sorted(set(old) | set(new)) - out = [] - for name in names: - if old.get(name) != new.get(name): - if name not in old: - out.append(f"`{name}` (added)") - elif name not in new: - out.append(f"`{name}` (removed)") - else: - out.append(f"`{name}`") - return out - - -def _fetch(store_url: str, digest: str) -> tuple[bytes | None, str]: - """ - Fetch a blob by digest. - - Returns a ``(payload, reason)`` pair, where ``payload`` is ``None`` on failure and - ``reason`` describes it. Cloudflare rejects the stdlib default agent, so one is set. - """ - url = f"{store_url.rstrip('/')}/{digest}" - request = urllib.request.Request(url, headers={"User-Agent": USER_AGENT}) # noqa: S310 - try: - with urllib.request.urlopen(request, timeout=60) as response: # noqa: S310 - return response.read(MAX_FETCH_BYTES + 1), "" - except urllib.error.HTTPError as exc: - return None, f"store returned HTTP {exc.code}" - except (urllib.error.URLError, TimeoutError, OSError) as exc: - return None, f"store unreachable ({exc})" - - -def _as_lines(raw: bytes, name: str) -> list[str]: - """ - Decode a blob into diffable lines. - - JSON is re-serialised with indentation first, because a minified bundle would otherwise - diff as a single unreadable line. - """ - text = raw.decode("utf-8", errors="replace") - if Path(name).suffix.lower() == ".json": - try: - text = json.dumps(json.loads(text), indent=2, sort_keys=True) - except json.JSONDecodeError: - pass - return text.splitlines() - - -def _text_diff(store_url: str, change: FileChange) -> tuple[str | None, str | None]: - """ - Build the unified diff for one text file. - - Returns a ``(diff, note)`` pair. Exactly one is set: ``note`` explains why no diff - could be produced (too large, or the store did not serve a blob). - """ - for entry in (change.old, change.new): - if entry is not None and entry.size > MAX_FETCH_BYTES: - return None, f"too large to diff ({entry.size:,} B)" - - old_raw, old_reason = _fetch(store_url, change.old.sha256) if change.old else (b"", "") - new_raw, new_reason = _fetch(store_url, change.new.sha256) if change.new else (b"", "") - if old_raw is None or new_raw is None: - return None, old_reason or new_reason - - lines = list( - difflib.unified_diff( - _as_lines(old_raw, change.name), - _as_lines(new_raw, change.name), - fromfile=f"old {change.old.sha256[:12] if change.old else '(absent)'}", - tofile=f"new {change.new.sha256[:12] if change.new else '(absent)'}", - lineterm="", - n=3, - ) - ) - if not lines: - return None, "identical after decoding" - if len(lines) > MAX_DIFF_LINES: - elided = len(lines) - MAX_DIFF_LINES - lines = [*lines[:MAX_DIFF_LINES], f"... {elided:,} more diff line(s) elided"] - return "\n".join(lines), None - - -def build_case_diff(repo: Repo, base: str, rel_path: str, store_url: str, fetch: bool) -> CaseDiff | None: - """ - Collect every change to one test case. - - A case deleted on this branch has no head manifest. It is still reported, as a removal, - because dropping a test case is a baseline change a reviewer needs to see. - Returns ``None`` only when the manifest is absent from both sides, which leaves nothing to say. - """ - head_path = Path(repo.working_tree_dir or ".") / rel_path - head = Manifest.load(head_path) if head_path.exists() else None - base_manifest = load_at_ref(repo, base, rel_path) - if head is None and base_manifest is None: - return None - - diff = CaseDiff( - label=case_label(rel_path), - rel_path=rel_path, - base=base_manifest, - head=head, - committed=_committed_changes(base_manifest, head), - metadata=_metadata_changes(base_manifest, head), - ) - - old_native = base_manifest.native if base_manifest else {} - new_native = head.native if head else {} - for name in sorted(set(old_native) | set(new_native)): - old, new = old_native.get(name), new_native.get(name) - if old is not None and new is not None and old.sha256 == new.sha256: - continue - change = FileChange(name=name, old=old, new=new) - if change.is_text: - if fetch: - change.diff, change.note = _text_diff(store_url, change) - else: - change.note = "fetching disabled" - diff.native.append(change) - - return diff - - -def _size_delta(change: FileChange) -> str: - """Render the size column for a native file.""" - if change.old is None: - return f"{change.new.size:,} B" # type: ignore[union-attr] - if change.new is None: - return f"was {change.old.size:,} B" - delta = change.new.size - change.old.size - return f"{change.old.size:,} -> {change.new.size:,} B ({delta:+,})" - - -def _blob_links(store_url: str, change: FileChange) -> str: - """Render download links for whichever blobs exist.""" - root = store_url.rstrip("/") - links = [] - if change.old: - links.append(f"[old]({root}/{change.old.sha256})") - if change.new: - links.append(f"[new]({root}/{change.new.sha256})") - return " ".join(links) - - -def _utf8_len(text: str) -> int: - """Return the UTF-8 byte length of ``text``, which is what GitHub's comment limit measures.""" - return len(text.encode("utf-8")) - - -def _counts(diff: CaseDiff) -> str: - """Summarise a case's native changes as a short ``+a ~c -r`` string.""" - tally = {"added": 0, "changed": 0, "removed": 0} - for change in diff.native: - tally[change.status] += 1 - parts = [ - f"+{tally['added']}" if tally["added"] else "", - f"~{tally['changed']}" if tally["changed"] else "", - f"-{tally['removed']}" if tally["removed"] else "", - ] - return " ".join(p for p in parts if p) or "none" - - -def render_summary(diffs: list[CaseDiff]) -> str: - """ - Render the one-row-per-case overview table. - - Every changed case appears here, whether or not its detail section survives the size cap, - so nothing is silently invisible. - """ - rows = ["| case | versions | native files |\n| --- | --- | --- |\n"] - for diff in diffs: - base_manifest, head_manifest = diff.base, diff.head - if head_manifest is None: - versions = "removed" - elif base_manifest is None: - versions = "new" - else: - versions = f"v{base_manifest.test_case_version} -> v{head_manifest.test_case_version}" - rows.append(f"| `{diff.label}` | {versions} | {_counts(diff)} |\n") - return "".join(rows) - - -def render_case(diff: CaseDiff, store_url: str) -> str: - """Render one test case as a collapsible markdown section.""" - text_changes = [c for c in diff.native if c.is_text] - binary_changes = [c for c in diff.native if not c.is_text] - headline = f"{len(diff.native)} native file(s)" - if diff.is_removed: - headline = f"removed case, {headline}" - elif diff.is_new: - headline = f"new case, {headline}" - - # The blank line after is load-bearing: GitHub parses markdown inside an HTML - # block only after one, so without it the first list renders as raw text with its backticks. - out = [f"
\n{diff.label} -- {headline}\n\n"] - - if diff.metadata: - out.append("".join(f"- {line}\n" for line in diff.metadata)) - if diff.committed: - out.append("\nCommitted artefacts changed:\n\n") - out.append("".join(f"- {name}\n" for name in diff.committed)) - - if binary_changes: - out.append("\n| file | status | size | blobs |\n| --- | --- | --- | --- |\n") - for change in binary_changes[:MAX_BINARY_ROWS]: - out.append( - f"| `{change.name}` | {change.status} | {_size_delta(change)} " - f"| {_blob_links(store_url, change)} |\n" - ) - if len(binary_changes) > MAX_BINARY_ROWS: - elided = len(binary_changes) - MAX_BINARY_ROWS - out.append(f"\n_{elided} further binary file(s) not listed._\n") - - for change in text_changes: - out.append(f"\n**`{change.name}`** ({change.status}, {_size_delta(change)})") - if change.diff: - out.append(f"\n\n```diff\n{change.diff}\n```\n") - else: - out.append(f" -- {change.note}, {_blob_links(store_url, change)}\n") - - out.append("\n
\n") - return "".join(out) - - -def _omission_notice(remaining: list[CaseDiff], budget: int) -> str: - """ - Render the notice naming the cases whose detail did not fit. - - Falls back to a bare count when the labels themselves would not fit ``budget``, because a - notice that overflows the limit costs the entire comment rather than just its own text. - """ - tail = "\n_The full report is attached to the workflow run as the `mint-diff` artefact._\n" - labels = ", ".join(f"`{d.label}`" for d in remaining) - listed = f"\n_Detail omitted to fit the comment size limit: {labels}._\n{tail}" - if _utf8_len(listed) <= budget: - return listed - return f"\n_Detail omitted for {len(remaining)} further case(s) to fit the comment size limit._\n{tail}" - - -def render(diffs: list[CaseDiff], base: str, store_url: str, max_bytes: int | None = None) -> str: - """ - Render the whole report. - - The summary table always covers every case. When ``max_bytes`` is set, detail sections are - appended only while the encoded report stays under it and the remainder is named rather than - expanded. Pass ``None`` for the full report, which is what the workflow artefact carries. - - The budget counts UTF-8 bytes rather than characters, because that is what GitHub's comment - limit measures and a diff may carry non-ASCII content. - """ - if not diffs: - return f"### Regression baseline diff\n\nNo baseline manifests changed against `{base}`.\n" - - diffs = sorted(diffs, key=lambda d: d.label) - total = sum(len(d.native) for d in diffs) - preamble = ( - "### Regression baseline diff\n\n" - f"{len(diffs)} test case(s) and {total} native file(s) changed against `{base}`. " - "Text outputs are diffed inline. NetCDF and PNG outputs are listed with a size delta " - "and a link to each blob.\n\n" - ) - header = f"{preamble}{render_summary(diffs)}\n" - - if max_bytes is not None and _utf8_len(header) > max_bytes: - # Enough cases that even the summary overflows. Keep the preamble and point at the - # artefact, because posting a comment that names nothing beats posting none at all. - return preamble + _omission_notice(diffs, max_bytes - _utf8_len(preamble)) - - # Hold back part of the budget for the omission notice. Without it the notice can push the - # report past the limit, and `gh pr comment` then rejects the whole thing. - notice_budget = max_bytes // 10 if max_bytes is not None else 0 - - used = _utf8_len(header) - body = "" - for index, diff in enumerate(diffs): - section = render_case(diff, store_url) - if max_bytes is not None and used + _utf8_len(section) > max_bytes - notice_budget: - body += _omission_notice(diffs[index:], notice_budget) - break - body += section - used += _utf8_len(section) - return header + body - - -def main(argv: list[str] | None = None) -> int: - """Entry point.""" - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--base", default=f"origin/{os.environ.get('GITHUB_BASE_REF', 'main')}") - parser.add_argument( - "--output", - type=Path, - default=None, - help="write the full, uncapped report here", - ) - parser.add_argument( - "--comment-output", - type=Path, - default=None, - help="write a copy capped to GitHub's comment size limit here", - ) - parser.add_argument("--store-url", default=os.environ.get("REF_NATIVE_STORE_URL", DEFAULT_STORE_URL)) - parser.add_argument("--no-fetch", action="store_true") - args = parser.parse_args(argv) - - repo = open_repo() - diffs = [] - for rel_path in changed_manifests(repo, args.base): - diff = build_case_diff(repo, args.base, rel_path, args.store_url, fetch=not args.no_fetch) - if diff is not None: - diffs.append(diff) - - full = render(diffs, args.base, args.store_url) - sys.stdout.write(full) - if args.output: - args.output.write_text(full, encoding="utf-8") - if args.comment_output: - capped = render(diffs, args.base, args.store_url, max_bytes=MAX_COMMENT_BYTES) - args.comment_output.write_text(capped, encoding="utf-8") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/scripts/generate_esgf_catalog.py b/scripts/generate_esgf_catalog.py index c4e561a74..71f46b4c2 100644 --- a/scripts/generate_esgf_catalog.py +++ b/scripts/generate_esgf_catalog.py @@ -35,6 +35,13 @@ def main() -> None: default=[], help="Directory containing obs4MIPs data (can be specified multiple times)", ) + parser.add_argument( + "--obs4ref-dir", + type=Path, + action="append", + default=[], + help="Directory containing obs4REF data (can be specified multiple times)", + ) parser.add_argument( "--pmp-climatology-dir", type=Path, @@ -80,6 +87,13 @@ def main() -> None: write_catalog_parquet(catalog, out_path) print(f" Wrote {len(catalog)} rows to {out_path}") + if args.obs4ref_dir: + print(f"Scanning obs4REF directories: {args.obs4ref_dir}") + catalog = generate_catalog("obs4ref", args.obs4ref_dir, strip_path_prefix=args.strip_prefix) + out_path = output_dir / "obs4ref_catalog.parquet" + write_catalog_parquet(catalog, out_path) + print(f" Wrote {len(catalog)} rows to {out_path}") + if args.pmp_climatology_dir: print(f"Scanning PMP climatology directories: {args.pmp_climatology_dir}") catalog = generate_catalog( diff --git a/tests/test-data/esgf-catalog/obs4mips_catalog.parquet b/tests/test-data/esgf-catalog/obs4mips_catalog.parquet index fbd84ae5c..88cecc5b0 100644 Binary files a/tests/test-data/esgf-catalog/obs4mips_catalog.parquet and b/tests/test-data/esgf-catalog/obs4mips_catalog.parquet differ diff --git a/tests/test-data/esgf-catalog/obs4ref_catalog.parquet b/tests/test-data/esgf-catalog/obs4ref_catalog.parquet new file mode 100644 index 000000000..e426e9660 Binary files /dev/null and b/tests/test-data/esgf-catalog/obs4ref_catalog.parquet differ diff --git a/uv.lock b/uv.lock index 55c5245d1..a10765111 100644 --- a/uv.lock +++ b/uv.lock @@ -163,6 +163,70 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl", hash = "sha256:749f0769958ebdc79c173ff0b0670d59051a535fa26e8eba02953dc19eb43205", size = 68797, upload-time = "2025-10-18T17:46:45.663Z" }, ] +[[package]] +name = "ast-serialize" +version = "0.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e1/a9/11851c3e02a3fea2ddc9932d1fdc7d2edaeecc0d2e11bc5f2a7fde2b0934/ast_serialize-0.8.0.tar.gz", hash = "sha256:6c37c43e4004dfb42d321ddedc569dc17ff4259296f3af577c9ea46a809bc010", size = 845638, upload-time = "2026-08-07T11:29:02.152Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/16/6e520b57cd8c75914b38c670ad4593d13c22911e4306cc7165dab8b0789b/ast_serialize-0.8.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:3d822605fa7bb326ef868d25fafced7fc660fa46d9b90c02ea86d5e2f5d325f7", size = 863924, upload-time = "2026-08-07T11:27:34.579Z" }, + { url = "https://files.pythonhosted.org/packages/03/e1/48802de9b22a2bcad42ec80601a17e3f69172fe4f590e6311bcc2b323aeb/ast_serialize-0.8.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:2efa40b068197d5efb62655b43baadb842ed71c4958cccd3e8b86a35726f0119", size = 1177662, upload-time = "2026-08-07T11:27:36.196Z" }, + { url = "https://files.pythonhosted.org/packages/38/d4/323438db76bded3a1f3523a3167b8325916b2ddceb2107a330c6ec9fcf4d/ast_serialize-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:db1b957291bca08c7e72f43a12357b2948e20775d970e3fc3dac0aa3160ab725", size = 1167072, upload-time = "2026-08-07T11:27:37.646Z" }, + { url = "https://files.pythonhosted.org/packages/77/82/53c5400b54144b56de8ed7f957fd1ccd97e42482009292ab46121d15f8dd/ast_serialize-0.8.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdc0d5b18ff8fb364e87923e47c0a91d0d69dbcaeaa274591f7fd26892cc3a3a", size = 1225497, upload-time = "2026-08-07T11:27:39.225Z" }, + { url = "https://files.pythonhosted.org/packages/44/5f/36c07327a8b91303fbf1382c7c3e8a2902072dbe1b9546138a5288e75ff0/ast_serialize-0.8.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9da7330f3e235bf7da89b8d39205c6350fc0c08a85379743f2df9fff87d6d980", size = 1227101, upload-time = "2026-08-07T11:27:40.799Z" }, + { url = "https://files.pythonhosted.org/packages/9d/48/5adf5c67addc7ddb328122208c6d375a84cf154984f412b4087330a157bd/ast_serialize-0.8.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f3186969ee66a9863b00acc6523ace44c56974eecb348a7ea4b228d9f0b80e19", size = 1424001, upload-time = "2026-08-07T11:27:42.708Z" }, + { url = "https://files.pythonhosted.org/packages/38/a1/70074dd3869d2b0e934f91891d8d6b734361cd3b80f85ca7ece2e668ecdd/ast_serialize-0.8.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40a57b73731be45da4fa41430c4d5dc94a24b3a4faba7b9e069978c0402064ea", size = 1245545, upload-time = "2026-08-07T11:27:44.4Z" }, + { url = "https://files.pythonhosted.org/packages/e3/be/53b9c0a8a6399950c2e3546bdfab96d2b299d5b114b47eb94fd3c49c4054/ast_serialize-0.8.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5075b9da3ef807eda752502446dfecea3b381c4900b7e27a5d5f4f899eb39951", size = 1248961, upload-time = "2026-08-07T11:27:45.781Z" }, + { url = "https://files.pythonhosted.org/packages/eb/13/3651d3812548a2bda15e26e5dd51aadb48cf682d0865370255fcf0e367dd/ast_serialize-0.8.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:293cc1c5bfa741f8e3fbe8175b9c07beee487c9a6fdbb25a5acad9f1df2d30a9", size = 1243877, upload-time = "2026-08-07T11:27:47.325Z" }, + { url = "https://files.pythonhosted.org/packages/21/a0/521f0bf000f675e9312a4aae2c8ba7a992405d072a85c485e08fd59433b9/ast_serialize-0.8.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0910c3442a75216dde0f102d854ba2aaa71d2482e0ee213630b9bf29584fba3", size = 1293903, upload-time = "2026-08-07T11:27:49.264Z" }, + { url = "https://files.pythonhosted.org/packages/b1/7e/402fc902568aa2ee65865a3e151f000db0153da8ce6b1be4c9c349025f8d/ast_serialize-0.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:43dd6d596879bb1cb8a12cc9dae7bb10090a39a35883026c24f82488a195619a", size = 1401070, upload-time = "2026-08-07T11:27:50.947Z" }, + { url = "https://files.pythonhosted.org/packages/ff/7c/97d4b66c057f1706fc8be6dd532cc77c988794357c8f4ffdb6adabb39562/ast_serialize-0.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:8c9d537f59e936392cfd3597789d1390304dd659efc3c486ce7f40fb6b8a9f53", size = 1502602, upload-time = "2026-08-07T11:27:52.364Z" }, + { url = "https://files.pythonhosted.org/packages/89/6f/72cc3b71562001bba46e898ccfbf1844f7939b3e28912736206102f2e5a8/ast_serialize-0.8.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:f0190a33d7f97c65e9069f7a7f40499eea6b5cbe260c558378109caf20ce934b", size = 1495848, upload-time = "2026-08-07T11:27:53.803Z" }, + { url = "https://files.pythonhosted.org/packages/a0/53/d6f629d1e49308b2f363dae028baa213ec222c9106fa1f7f0d1f7b41499a/ast_serialize-0.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:77308ae6c5cf5264cc0f01a7c556ec77a9e68eb1f61b093534d698139fdc3b14", size = 1556556, upload-time = "2026-08-07T11:27:55.342Z" }, + { url = "https://files.pythonhosted.org/packages/ee/22/340f35dd8dfc6d412d53dc20699ca014b8d228db923e8ed4759c512b162c/ast_serialize-0.8.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:8d53a23f27e1ed3a36b2d26fd2a1a6228c8e85a1ed62ff7cdb44bd610769f20a", size = 1417822, upload-time = "2026-08-07T11:27:56.712Z" }, + { url = "https://files.pythonhosted.org/packages/11/29/6dde5c13fbebc051d3a6df4ec0a6fd1d5359333cc1193f7f609f3410b4d8/ast_serialize-0.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ffa5e7cb08f96fed9121f77b224151e41caf88feab9d652bb46c78202b6fbeda", size = 1445153, upload-time = "2026-08-07T11:27:58.275Z" }, + { url = "https://files.pythonhosted.org/packages/62/c5/f473a8ed030f7a0ca24b9849cca184677a50c053867a7b808c2e1289bbd3/ast_serialize-0.8.0-cp314-cp314t-win32.whl", hash = "sha256:fa70ed4dea0bb18b30a1789c77baa701d0ef30c474f2ccabdea61e25623a8827", size = 1063711, upload-time = "2026-08-07T11:27:59.793Z" }, + { url = "https://files.pythonhosted.org/packages/23/63/39e171fcd38ca057c2e1979d5ee81ac7a3502784abe3d83df7454f7a0978/ast_serialize-0.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d8b3c8eee4c1baef9d4e84d2a59a805501617127be42615cb48970b15b0892b6", size = 1103740, upload-time = "2026-08-07T11:28:01.405Z" }, + { url = "https://files.pythonhosted.org/packages/21/1c/d00762b399e7726d68d0a088cc946e3a4c60f1c6176f557608f672f627f3/ast_serialize-0.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:ac4f0a83c55a9b782f79ad55a5247b7db123c1db405959791c2ef886e9710c9f", size = 1076021, upload-time = "2026-08-07T11:28:02.947Z" }, + { url = "https://files.pythonhosted.org/packages/4c/11/911210c3c78923273a9211a2b6cfc4c8aa723b30dab3e1c8d19afb983b40/ast_serialize-0.8.0-cp315-abi3.abi3t-macosx_10_12_x86_64.whl", hash = "sha256:86b8a1e6d90467345356098b040150e82fbc26d24a7a202224b13dc1f6264ca0", size = 1177715, upload-time = "2026-08-07T11:28:04.654Z" }, + { url = "https://files.pythonhosted.org/packages/77/89/6282881c8587606638db153cbe21e1e0c4d1f3970dee1aa0610a1c62a026/ast_serialize-0.8.0-cp315-abi3.abi3t-macosx_11_0_arm64.whl", hash = "sha256:39e92ff8e8cb45947fe9007174b2950e1fb098e6abd00266a13cd3bcf6675068", size = 1169347, upload-time = "2026-08-07T11:28:06.1Z" }, + { url = "https://files.pythonhosted.org/packages/97/78/a9f846a03a340ff3728c915f23338ca742742f3292700559cdb3ad999b1e/ast_serialize-0.8.0-cp315-abi3.abi3t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c85d8d18db5b2dfcb3b7e38a4d600ca35504c0ed8a6f75cd1c811e4ffe248a15", size = 1225916, upload-time = "2026-08-07T11:28:07.654Z" }, + { url = "https://files.pythonhosted.org/packages/c0/15/aba6ef8a988a6eceb6f0359589aac509e29ae2dba67fd9bfd5af0c3f13e7/ast_serialize-0.8.0-cp315-abi3.abi3t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9830ff7e764f74d9eefb01170c61a9f0fd2c027dac5fcb72e064decd57d56371", size = 1227135, upload-time = "2026-08-07T11:28:09.504Z" }, + { url = "https://files.pythonhosted.org/packages/94/29/3f63d696ea7c5b8abadcecc3505be51bd900daaccc522ed8322fa5b05a93/ast_serialize-0.8.0-cp315-abi3.abi3t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6479d9722a4cd21b578f5478074c41e6169f04811996ec881655560f703a5bba", size = 1425040, upload-time = "2026-08-07T11:28:11.044Z" }, + { url = "https://files.pythonhosted.org/packages/e2/5d/0aac338604ff59df5774d4304307898982252f325ff7cafe31d52fedcb65/ast_serialize-0.8.0-cp315-abi3.abi3t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a63bed264e818cd83eec11feed0f50aa162542b91132ef58afebc857182763a5", size = 1246278, upload-time = "2026-08-07T11:28:12.519Z" }, + { url = "https://files.pythonhosted.org/packages/23/ca/9f1ef795bb724719532bd86dbec11e5b66857d3fbe9b6772baec0191a6ed/ast_serialize-0.8.0-cp315-abi3.abi3t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d187197d234aa45d6cfa2b096be5f666e8cc2e7eb3722d0ab8926293cf5720c", size = 1250029, upload-time = "2026-08-07T11:28:13.896Z" }, + { url = "https://files.pythonhosted.org/packages/dc/25/5e061372d2ed953b9ba3b9c4f73de3b8e9234cda3f6c088db4686801d0e1/ast_serialize-0.8.0-cp315-abi3.abi3t-manylinux_2_31_riscv64.whl", hash = "sha256:2d39a56282cfcc0d8eeea37267c754be59c98d48505c23b1dae5c6011f3813dd", size = 1243575, upload-time = "2026-08-07T11:28:15.37Z" }, + { url = "https://files.pythonhosted.org/packages/a8/c1/ae7da218053120635a4ca802366c69f707203641af95372eeb83f70dfd52/ast_serialize-0.8.0-cp315-abi3.abi3t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f7cc5f10386994c0f4844f1e6d6a97127e9b478660eb6dec2b257644f0acab64", size = 1294396, upload-time = "2026-08-07T11:28:16.813Z" }, + { url = "https://files.pythonhosted.org/packages/2e/89/271d1f49c5269fcddcc789ea3f25be401f6723fc1138aeda539f4d05516d/ast_serialize-0.8.0-cp315-abi3.abi3t-musllinux_1_2_aarch64.whl", hash = "sha256:6102f2f985c2e542be85cd857678ec9356fefa792b93cadfadd31139f5696f27", size = 1401987, upload-time = "2026-08-07T11:28:18.333Z" }, + { url = "https://files.pythonhosted.org/packages/55/be/4e7d77fcf571ac7cb5cf7115a20c36642bd7d29473b45dfaaefeb9618f90/ast_serialize-0.8.0-cp315-abi3.abi3t-musllinux_1_2_armv7l.whl", hash = "sha256:3a8660fe66667b76a6e9dccd1d33e66b229fde3b308db991c041609226c005b6", size = 1502904, upload-time = "2026-08-07T11:28:20.039Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ae/ed1de2db7e019d4236fbc164ffa5ef9a6022a300a342bbf142d21b7c141e/ast_serialize-0.8.0-cp315-abi3.abi3t-musllinux_1_2_i686.whl", hash = "sha256:e7266307e5fba39836edb79def8608887af48820508bff3c5f2941e1e04d1534", size = 1496967, upload-time = "2026-08-07T11:28:21.734Z" }, + { url = "https://files.pythonhosted.org/packages/92/89/5fea507fae5c5f18b7dc7f95e5c00956574b8c717b8fd2049c504fab0b18/ast_serialize-0.8.0-cp315-abi3.abi3t-musllinux_1_2_ppc64le.whl", hash = "sha256:4ca7e6fd1ad845d1cc649dc2ecd499db2f8f46af5bf8da7b70dd858774cc038b", size = 1559041, upload-time = "2026-08-07T11:28:23.194Z" }, + { url = "https://files.pythonhosted.org/packages/42/71/478d69df21b64e064554a68134c94be304270316ca676a94e63c389a636a/ast_serialize-0.8.0-cp315-abi3.abi3t-musllinux_1_2_riscv64.whl", hash = "sha256:2880350b13d3eae69a0d70bc1fb6c9bfaca4dbd0e20ba8cd1aa483080b56ff06", size = 1417367, upload-time = "2026-08-07T11:28:24.601Z" }, + { url = "https://files.pythonhosted.org/packages/5e/2d/8962dc8d5b3a9dc27b36f9db199afa25264c741505469d9ec10ffbfd2ba7/ast_serialize-0.8.0-cp315-abi3.abi3t-musllinux_1_2_x86_64.whl", hash = "sha256:ab0f9a59f7d63d0d441b56b9a818b273705264352d5115cfee12e940e816d958", size = 1446178, upload-time = "2026-08-07T11:28:26.152Z" }, + { url = "https://files.pythonhosted.org/packages/4f/22/14d2ad4fd1d1bcd0dc687ca268e0630069f45162496260c0efb70ee0ea72/ast_serialize-0.8.0-cp315-abi3.abi3t-win32.whl", hash = "sha256:0485a25ef519c62e749ee3c1ad8070e591b380d67226349eb5a70b228dc1ac4a", size = 1063811, upload-time = "2026-08-07T11:28:27.864Z" }, + { url = "https://files.pythonhosted.org/packages/18/1d/84a327c0202a41aa5fdba3ade33904d6d8f3b9e6806fa83568d835395850/ast_serialize-0.8.0-cp315-abi3.abi3t-win_amd64.whl", hash = "sha256:bd84d60bca7079e741be4ac5dbe237751a59d7f6f9f0126b11880d63822cbe16", size = 1105518, upload-time = "2026-08-07T11:28:29.691Z" }, + { url = "https://files.pythonhosted.org/packages/8c/92/74556dec52fde85a2ad84ed159991b916241043788609c15d8b77e14570b/ast_serialize-0.8.0-cp315-abi3.abi3t-win_arm64.whl", hash = "sha256:057769b5921336eb2d9124f2a731b42ed05ffdac559b840dbdf6f3937cf153dc", size = 1076319, upload-time = "2026-08-07T11:28:31.282Z" }, + { url = "https://files.pythonhosted.org/packages/d1/5d/c650b1f2cc1e75193358da95a080261422e8cd10b66d7370b1688c9915c5/ast_serialize-0.8.0-cp315-cp315-pyemscripten_2026_5_wasm32.whl", hash = "sha256:a02cbed7d8bfdcdee88edaac12bd50d53d9953aaa2e1852ef078625be5f1c0b5", size = 852914, upload-time = "2026-08-07T11:28:32.929Z" }, + { url = "https://files.pythonhosted.org/packages/d9/e3/6142e920fec6ef7bccabd8c24ed8ed99f8bdc6cb8b065e1df7c6a3b2d667/ast_serialize-0.8.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:e1bd223df0f6c96b396975fa604cb33bce53d9b4a0185490be4c4a289f7c9c87", size = 1184007, upload-time = "2026-08-07T11:28:34.654Z" }, + { url = "https://files.pythonhosted.org/packages/a6/e9/6e8be8df02b35d85e2b8809f7f1cfa290bdf5882b55127a539d049482db0/ast_serialize-0.8.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:ddd3b61f45c132da66c5476b281891e08c1fd87fbdabe8a6973e1622efc85f06", size = 1177588, upload-time = "2026-08-07T11:28:36.318Z" }, + { url = "https://files.pythonhosted.org/packages/8c/80/7e0fd2e2e2aba257820db4a8657c4c356844d36b914b20a4af294bcfb902/ast_serialize-0.8.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f9caa63fad8241257ae401b5ff0a64026c6adb36b8e86cbe8782d9ea505daf6", size = 1234575, upload-time = "2026-08-07T11:28:37.772Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6a/3bae0af06f9b1bae3001c44d64215f5b567877e7aae9ffd45db11c3a7647/ast_serialize-0.8.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3926fa117b5e65019853a2969966d11c7175af377a3425991f3fe73784412405", size = 1236015, upload-time = "2026-08-07T11:28:39.14Z" }, + { url = "https://files.pythonhosted.org/packages/6f/c4/ce2d41a1bc22508e82618901f7e10f2a5e2f9556553fea90624daf9875e2/ast_serialize-0.8.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:485f1113af805e9e170b95ef993ca3fbd4f89c04bab25c58b4fc632d854801ab", size = 1432808, upload-time = "2026-08-07T11:28:40.664Z" }, + { url = "https://files.pythonhosted.org/packages/1a/90/f5058f209756dd70e958b7538aaa82d25d24944baf9ec8ae6f27b06fcacc/ast_serialize-0.8.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ccebbed24f1281062d5852353c72c47502955926cfcb8345ffb3a44d87ff3d3", size = 1256251, upload-time = "2026-08-07T11:28:42.223Z" }, + { url = "https://files.pythonhosted.org/packages/bf/32/7f77ea87fa0836daab706ed5cb7f903bb25fa26a77439011aee626af11d8/ast_serialize-0.8.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:252f883290d1cdb728eb7fe1d9a7221b88af5a329aae0bc91ddee4dafb820331", size = 1258574, upload-time = "2026-08-07T11:28:43.751Z" }, + { url = "https://files.pythonhosted.org/packages/eb/5a/75b82ad2725b5e8e8c742732f9e76c6738a292d0709e1f60d10a973730b4/ast_serialize-0.8.0-cp39-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:96abc072ad29db8d02194afd47d68987322622787daceae82398d7b69f3ba2e6", size = 1254075, upload-time = "2026-08-07T11:28:45.28Z" }, + { url = "https://files.pythonhosted.org/packages/4e/54/8c20ed4eea805516a3fd23dd4a721ce28c64f50f0e4b359969f60a8c97a6/ast_serialize-0.8.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9118ad3e369727060b2696fc4078f250ecffca4248ba87f537f55cea9f9dce06", size = 1301018, upload-time = "2026-08-07T11:28:46.851Z" }, + { url = "https://files.pythonhosted.org/packages/cb/5b/9f14430f12fe830b656fb38f8e2e05ee13b02a88967660bef46af0ab22a8/ast_serialize-0.8.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f359df4bd921918af8bebd142a376c77511d7151cc8ba852760b587b5a4a54f3", size = 1409951, upload-time = "2026-08-07T11:28:48.312Z" }, + { url = "https://files.pythonhosted.org/packages/2d/3d/084882eca93c842bd4262591a071ec7f825340644035e51501208cc5a8d4/ast_serialize-0.8.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:e94f9121d13fa36cbf21314783c77d05ae3a0868decd18cf5233fdcc6de49ac8", size = 1509544, upload-time = "2026-08-07T11:28:49.847Z" }, + { url = "https://files.pythonhosted.org/packages/ce/73/ea84852096c2036c61cc0b2f97b90242207419f534dc671060ee1c8e05cb/ast_serialize-0.8.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:54f95b486018d262bcb387a9afd96f0da74508b442762b80c769454a6fbb3ee3", size = 1505671, upload-time = "2026-08-07T11:28:51.239Z" }, + { url = "https://files.pythonhosted.org/packages/cb/88/287b9a5300c1f2f651d259f670931b63110adc265b7613c885b44c5bc53d/ast_serialize-0.8.0-cp39-abi3-musllinux_1_2_ppc64le.whl", hash = "sha256:4c38b915511e32bc718c49dbce98ff9af36bac0ad6a604f58000cd5e3aecdba7", size = 1563685, upload-time = "2026-08-07T11:28:53.112Z" }, + { url = "https://files.pythonhosted.org/packages/ee/f3/1bc3a79afcf0c2a8d2c37182d0d659d1545a9d7f7f6dc9cf3e63d6c17135/ast_serialize-0.8.0-cp39-abi3-musllinux_1_2_riscv64.whl", hash = "sha256:9a2ef9cf12f2de4f1028c42c1dd7d775255e0fb3e5bb48896c97e35ef52366fe", size = 1427977, upload-time = "2026-08-07T11:28:54.418Z" }, + { url = "https://files.pythonhosted.org/packages/5c/cd/440c798957e14e31776bfeb024d8fafe0bb1d5b89c51c2f067e69938f7b0/ast_serialize-0.8.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6f18048fe9f6dd266bd577cdec48bdcecb74faaa01fe941324435483b013ed2a", size = 1454335, upload-time = "2026-08-07T11:28:55.968Z" }, + { url = "https://files.pythonhosted.org/packages/4f/4a/587eb36dcc240a54c8660f599464516b469ecad96f0dbdb6bccbedb50745/ast_serialize-0.8.0-cp39-abi3-win32.whl", hash = "sha256:31883542dd6c94d178f5db3d32fbd69c5eb88b3a7c018e7ac8cc0c45195ddbed", size = 1068858, upload-time = "2026-08-07T11:28:57.541Z" }, + { url = "https://files.pythonhosted.org/packages/5f/a4/3e887bbd92164e183cb6e412c6a3e9198ddd446d7fe405958293ef5ef49c/ast_serialize-0.8.0-cp39-abi3-win_amd64.whl", hash = "sha256:861794565b06337005c1447ef23103a3d5a627d08bdc827870d00d0b28ef5f51", size = 1111839, upload-time = "2026-08-07T11:28:59Z" }, + { url = "https://files.pythonhosted.org/packages/25/6c/b400476d3ceba681ab929787edc9554f6d88fcc69435eb681b00fc0457a5/ast_serialize-0.8.0-cp39-abi3-win_arm64.whl", hash = "sha256:b2a5978662fd4db463dfb4b974d2b10ac6430b98f5333aabc7051909df3561d0", size = 1083655, upload-time = "2026-08-07T11:29:00.349Z" }, +] + [[package]] name = "asttokens" version = "3.0.1" @@ -656,6 +720,7 @@ dependencies = [ { name = "climate-ref-core" }, { name = "environs" }, { name = "gitpython" }, + { name = "jinja2" }, { name = "loguru" }, { name = "netcdf4" }, { name = "parsl", marker = "sys_platform != 'win32'" }, @@ -664,6 +729,7 @@ dependencies = [ { name = "tomlkit" }, { name = "tqdm" }, { name = "typer" }, + { name = "xarray" }, ] [package.optional-dependencies] @@ -706,6 +772,7 @@ requires-dist = [ { name = "climate-ref-pmp", marker = "extra == 'providers'", editable = "packages/climate-ref-pmp" }, { name = "environs", specifier = ">=11.0.0" }, { name = "gitpython", specifier = ">=3.1.58" }, + { name = "jinja2", specifier = ">=3.1" }, { name = "loguru", specifier = ">=0.7.2" }, { name = "netcdf4", specifier = ">=1.6.0" }, { name = "parsl", marker = "sys_platform != 'win32'", specifier = ">=2025.5.19" }, @@ -717,6 +784,7 @@ requires-dist = [ { name = "tomlkit", specifier = ">=0.13.2" }, { name = "tqdm", specifier = ">=4.67.1" }, { name = "typer", specifier = ">=0.12.5" }, + { name = "xarray", specifier = ">=2025.1" }, ] provides-extras = ["postgres", "celery", "aft-providers", "providers", "test"] @@ -1011,7 +1079,7 @@ dev = [ { name = "mkdocs-section-index", specifier = ">=0.3.12" }, { name = "mkdocs-typer2", specifier = ">=0.3.0" }, { name = "mkdocstrings", extras = ["python"], specifier = ">=1.0.4" }, - { name = "mypy", specifier = ">=1.20.1" }, + { name = "mypy", specifier = ">=2.3.1" }, { name = "notebook", specifier = ">=7.5.6" }, { name = "pandas-indexing", specifier = ">=0.6.3" }, { name = "pandas-stubs", specifier = ">=2.2.3" }, @@ -1551,14 +1619,14 @@ wheels = [ [[package]] name = "gitpython" -version = "3.1.58" +version = "3.1.61" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "gitdb" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/26/d6/5f358ff283325580c2003a6d953aea18cfe10ae87b46f5ebc80fa3a386dc/gitpython-3.1.58.tar.gz", hash = "sha256:621416df10ef3fd0e19fabf9172ddeed0fa704d353d04f194eec56a625a95b22", size = 228498, upload-time = "2026-08-04T15:05:49.47Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/61/3285044215fb596bf093e39ccb96ece0a1076a8ca57a61e069a6a33cdb1b/gitpython-3.1.61.tar.gz", hash = "sha256:f51c24d8c0f733a195447385f5774a5dfe8767f5acfd7994a33755644c6ecc95", size = 231680, upload-time = "2026-08-28T11:01:13.761Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/0c/9d8752098bc442f0726e64aa6135940b3a96809915d1aa4206c1bb97881d/gitpython-3.1.58-py3-none-any.whl", hash = "sha256:d331e722577f0fd7fc1f857419b3ecc07af66282b933d2a4d95f84a042fdd50f", size = 220183, upload-time = "2026-08-04T15:05:48.025Z" }, + { url = "https://files.pythonhosted.org/packages/6f/5e/49cc172da4d0578644ba37cec5cb365b1fefc603b26edea9bcac1c7f830a/gitpython-3.1.61-py3-none-any.whl", hash = "sha256:8ab28c9da863cdd9e7d7694ec46cf3e6c9a12d8a30a1acd3447aec11975d530c", size = 222118, upload-time = "2026-08-28T11:01:12.262Z" }, ] [[package]] @@ -2196,62 +2264,103 @@ wheels = [ [[package]] name = "librt" -version = "0.8.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/56/9c/b4b0c54d84da4a94b37bd44151e46d5e583c9534c7e02250b961b1b6d8a8/librt-0.8.1.tar.gz", hash = "sha256:be46a14693955b3bd96014ccbdb8339ee8c9346fbe11c1b78901b55125f14c73", size = 177471, upload-time = "2026-02-17T16:13:06.101Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/21/d39b0a87ac52fc98f621fb6f8060efb017a767ebbbac2f99fbcbc9ddc0d7/librt-0.8.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a28f2612ab566b17f3698b0da021ff9960610301607c9a5e8eaca62f5e1c350a", size = 66516, upload-time = "2026-02-17T16:11:41.604Z" }, - { url = "https://files.pythonhosted.org/packages/69/f1/46375e71441c43e8ae335905e069f1c54febee63a146278bcee8782c84fd/librt-0.8.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:60a78b694c9aee2a0f1aaeaa7d101cf713e92e8423a941d2897f4fa37908dab9", size = 68634, upload-time = "2026-02-17T16:11:43.268Z" }, - { url = "https://files.pythonhosted.org/packages/0a/33/c510de7f93bf1fa19e13423a606d8189a02624a800710f6e6a0a0f0784b3/librt-0.8.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:758509ea3f1eba2a57558e7e98f4659d0ea7670bff49673b0dde18a3c7e6c0eb", size = 198941, upload-time = "2026-02-17T16:11:44.28Z" }, - { url = "https://files.pythonhosted.org/packages/dd/36/e725903416409a533d92398e88ce665476f275081d0d7d42f9c4951999e5/librt-0.8.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:039b9f2c506bd0ab0f8725aa5ba339c6f0cd19d3b514b50d134789809c24285d", size = 209991, upload-time = "2026-02-17T16:11:45.462Z" }, - { url = "https://files.pythonhosted.org/packages/30/7a/8d908a152e1875c9f8eac96c97a480df425e657cdb47854b9efaa4998889/librt-0.8.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bb54f1205a3a6ab41a6fd71dfcdcbd278670d3a90ca502a30d9da583105b6f7", size = 224476, upload-time = "2026-02-17T16:11:46.542Z" }, - { url = "https://files.pythonhosted.org/packages/a8/b8/a22c34f2c485b8903a06f3fe3315341fe6876ef3599792344669db98fcff/librt-0.8.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:05bd41cdee35b0c59c259f870f6da532a2c5ca57db95b5f23689fcb5c9e42440", size = 217518, upload-time = "2026-02-17T16:11:47.746Z" }, - { url = "https://files.pythonhosted.org/packages/79/6f/5c6fea00357e4f82ba44f81dbfb027921f1ab10e320d4a64e1c408d035d9/librt-0.8.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adfab487facf03f0d0857b8710cf82d0704a309d8ffc33b03d9302b4c64e91a9", size = 225116, upload-time = "2026-02-17T16:11:49.298Z" }, - { url = "https://files.pythonhosted.org/packages/f2/a0/95ced4e7b1267fe1e2720a111685bcddf0e781f7e9e0ce59d751c44dcfe5/librt-0.8.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:153188fe98a72f206042be10a2c6026139852805215ed9539186312d50a8e972", size = 217751, upload-time = "2026-02-17T16:11:50.49Z" }, - { url = "https://files.pythonhosted.org/packages/93/c2/0517281cb4d4101c27ab59472924e67f55e375bc46bedae94ac6dc6e1902/librt-0.8.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:dd3c41254ee98604b08bd5b3af5bf0a89740d4ee0711de95b65166bf44091921", size = 218378, upload-time = "2026-02-17T16:11:51.783Z" }, - { url = "https://files.pythonhosted.org/packages/43/e8/37b3ac108e8976888e559a7b227d0ceac03c384cfd3e7a1c2ee248dbae79/librt-0.8.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e0d138c7ae532908cbb342162b2611dbd4d90c941cd25ab82084aaf71d2c0bd0", size = 241199, upload-time = "2026-02-17T16:11:53.561Z" }, - { url = "https://files.pythonhosted.org/packages/4b/5b/35812d041c53967fedf551a39399271bbe4257e681236a2cf1a69c8e7fa1/librt-0.8.1-cp312-cp312-win32.whl", hash = "sha256:43353b943613c5d9c49a25aaffdba46f888ec354e71e3529a00cca3f04d66a7a", size = 54917, upload-time = "2026-02-17T16:11:54.758Z" }, - { url = "https://files.pythonhosted.org/packages/de/d1/fa5d5331b862b9775aaf2a100f5ef86854e5d4407f71bddf102f4421e034/librt-0.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:ff8baf1f8d3f4b6b7257fcb75a501f2a5499d0dda57645baa09d4d0d34b19444", size = 62017, upload-time = "2026-02-17T16:11:55.748Z" }, - { url = "https://files.pythonhosted.org/packages/c7/7c/c614252f9acda59b01a66e2ddfd243ed1c7e1deab0293332dfbccf862808/librt-0.8.1-cp312-cp312-win_arm64.whl", hash = "sha256:0f2ae3725904f7377e11cc37722d5d401e8b3d5851fb9273d7f4fe04f6b3d37d", size = 52441, upload-time = "2026-02-17T16:11:56.801Z" }, - { url = "https://files.pythonhosted.org/packages/c5/3c/f614c8e4eaac7cbf2bbdf9528790b21d89e277ee20d57dc6e559c626105f/librt-0.8.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7e6bad1cd94f6764e1e21950542f818a09316645337fd5ab9a7acc45d99a8f35", size = 66529, upload-time = "2026-02-17T16:11:57.809Z" }, - { url = "https://files.pythonhosted.org/packages/ab/96/5836544a45100ae411eda07d29e3d99448e5258b6e9c8059deb92945f5c2/librt-0.8.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cf450f498c30af55551ba4f66b9123b7185362ec8b625a773b3d39aa1a717583", size = 68669, upload-time = "2026-02-17T16:11:58.843Z" }, - { url = "https://files.pythonhosted.org/packages/06/53/f0b992b57af6d5531bf4677d75c44f095f2366a1741fb695ee462ae04b05/librt-0.8.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:eca45e982fa074090057132e30585a7e8674e9e885d402eae85633e9f449ce6c", size = 199279, upload-time = "2026-02-17T16:11:59.862Z" }, - { url = "https://files.pythonhosted.org/packages/f3/ad/4848cc16e268d14280d8168aee4f31cea92bbd2b79ce33d3e166f2b4e4fc/librt-0.8.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c3811485fccfda840861905b8c70bba5ec094e02825598bb9d4ca3936857a04", size = 210288, upload-time = "2026-02-17T16:12:00.954Z" }, - { url = "https://files.pythonhosted.org/packages/52/05/27fdc2e95de26273d83b96742d8d3b7345f2ea2bdbd2405cc504644f2096/librt-0.8.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e4af413908f77294605e28cfd98063f54b2c790561383971d2f52d113d9c363", size = 224809, upload-time = "2026-02-17T16:12:02.108Z" }, - { url = "https://files.pythonhosted.org/packages/7a/d0/78200a45ba3240cb042bc597d6f2accba9193a2c57d0356268cbbe2d0925/librt-0.8.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5212a5bd7fae98dae95710032902edcd2ec4dc994e883294f75c857b83f9aba0", size = 218075, upload-time = "2026-02-17T16:12:03.631Z" }, - { url = "https://files.pythonhosted.org/packages/af/72/a210839fa74c90474897124c064ffca07f8d4b347b6574d309686aae7ca6/librt-0.8.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e692aa2d1d604e6ca12d35e51fdc36f4cda6345e28e36374579f7ef3611b3012", size = 225486, upload-time = "2026-02-17T16:12:04.725Z" }, - { url = "https://files.pythonhosted.org/packages/a3/c1/a03cc63722339ddbf087485f253493e2b013039f5b707e8e6016141130fa/librt-0.8.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4be2a5c926b9770c9e08e717f05737a269b9d0ebc5d2f0060f0fe3fe9ce47acb", size = 218219, upload-time = "2026-02-17T16:12:05.828Z" }, - { url = "https://files.pythonhosted.org/packages/58/f5/fff6108af0acf941c6f274a946aea0e484bd10cd2dc37610287ce49388c5/librt-0.8.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fd1a720332ea335ceb544cf0a03f81df92abd4bb887679fd1e460976b0e6214b", size = 218750, upload-time = "2026-02-17T16:12:07.09Z" }, - { url = "https://files.pythonhosted.org/packages/71/67/5a387bfef30ec1e4b4f30562c8586566faf87e47d696768c19feb49e3646/librt-0.8.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2af9e01e0ef80d95ae3c720be101227edae5f2fe7e3dc63d8857fadfc5a1d", size = 241624, upload-time = "2026-02-17T16:12:08.43Z" }, - { url = "https://files.pythonhosted.org/packages/d4/be/24f8502db11d405232ac1162eb98069ca49c3306c1d75c6ccc61d9af8789/librt-0.8.1-cp313-cp313-win32.whl", hash = "sha256:086a32dbb71336627e78cc1d6ee305a68d038ef7d4c39aaff41ae8c9aa46e91a", size = 54969, upload-time = "2026-02-17T16:12:09.633Z" }, - { url = "https://files.pythonhosted.org/packages/5c/73/c9fdf6cb2a529c1a092ce769a12d88c8cca991194dfe641b6af12fa964d2/librt-0.8.1-cp313-cp313-win_amd64.whl", hash = "sha256:e11769a1dbda4da7b00a76cfffa67aa47cfa66921d2724539eee4b9ede780b79", size = 62000, upload-time = "2026-02-17T16:12:10.632Z" }, - { url = "https://files.pythonhosted.org/packages/d3/97/68f80ca3ac4924f250cdfa6e20142a803e5e50fca96ef5148c52ee8c10ea/librt-0.8.1-cp313-cp313-win_arm64.whl", hash = "sha256:924817ab3141aca17893386ee13261f1d100d1ef410d70afe4389f2359fea4f0", size = 52495, upload-time = "2026-02-17T16:12:11.633Z" }, - { url = "https://files.pythonhosted.org/packages/c9/6a/907ef6800f7bca71b525a05f1839b21f708c09043b1c6aa77b6b827b3996/librt-0.8.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6cfa7fe54fd4d1f47130017351a959fe5804bda7a0bc7e07a2cdbc3fdd28d34f", size = 66081, upload-time = "2026-02-17T16:12:12.766Z" }, - { url = "https://files.pythonhosted.org/packages/1b/18/25e991cd5640c9fb0f8d91b18797b29066b792f17bf8493da183bf5caabe/librt-0.8.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:228c2409c079f8c11fb2e5d7b277077f694cb93443eb760e00b3b83cb8b3176c", size = 68309, upload-time = "2026-02-17T16:12:13.756Z" }, - { url = "https://files.pythonhosted.org/packages/a4/36/46820d03f058cfb5a9de5940640ba03165ed8aded69e0733c417bb04df34/librt-0.8.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7aae78ab5e3206181780e56912d1b9bb9f90a7249ce12f0e8bf531d0462dd0fc", size = 196804, upload-time = "2026-02-17T16:12:14.818Z" }, - { url = "https://files.pythonhosted.org/packages/59/18/5dd0d3b87b8ff9c061849fbdb347758d1f724b9a82241aa908e0ec54ccd0/librt-0.8.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:172d57ec04346b047ca6af181e1ea4858086c80bdf455f61994c4aa6fc3f866c", size = 206907, upload-time = "2026-02-17T16:12:16.513Z" }, - { url = "https://files.pythonhosted.org/packages/d1/96/ef04902aad1424fd7299b62d1890e803e6ab4018c3044dca5922319c4b97/librt-0.8.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6b1977c4ea97ce5eb7755a78fae68d87e4102e4aaf54985e8b56806849cc06a3", size = 221217, upload-time = "2026-02-17T16:12:17.906Z" }, - { url = "https://files.pythonhosted.org/packages/6d/ff/7e01f2dda84a8f5d280637a2e5827210a8acca9a567a54507ef1c75b342d/librt-0.8.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:10c42e1f6fd06733ef65ae7bebce2872bcafd8d6e6b0a08fe0a05a23b044fb14", size = 214622, upload-time = "2026-02-17T16:12:19.108Z" }, - { url = "https://files.pythonhosted.org/packages/1e/8c/5b093d08a13946034fed57619742f790faf77058558b14ca36a6e331161e/librt-0.8.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4c8dfa264b9193c4ee19113c985c95f876fae5e51f731494fc4e0cf594990ba7", size = 221987, upload-time = "2026-02-17T16:12:20.331Z" }, - { url = "https://files.pythonhosted.org/packages/d3/cc/86b0b3b151d40920ad45a94ce0171dec1aebba8a9d72bb3fa00c73ab25dd/librt-0.8.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:01170b6729a438f0dedc4a26ed342e3dc4f02d1000b4b19f980e1877f0c297e6", size = 215132, upload-time = "2026-02-17T16:12:21.54Z" }, - { url = "https://files.pythonhosted.org/packages/fc/be/8588164a46edf1e69858d952654e216a9a91174688eeefb9efbb38a9c799/librt-0.8.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:7b02679a0d783bdae30d443025b94465d8c3dc512f32f5b5031f93f57ac32071", size = 215195, upload-time = "2026-02-17T16:12:23.073Z" }, - { url = "https://files.pythonhosted.org/packages/f5/f2/0b9279bea735c734d69344ecfe056c1ba211694a72df10f568745c899c76/librt-0.8.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:190b109bb69592a3401fe1ffdea41a2e73370ace2ffdc4a0e8e2b39cdea81b78", size = 237946, upload-time = "2026-02-17T16:12:24.275Z" }, - { url = "https://files.pythonhosted.org/packages/e9/cc/5f2a34fbc8aeb35314a3641f9956fa9051a947424652fad9882be7a97949/librt-0.8.1-cp314-cp314-win32.whl", hash = "sha256:e70a57ecf89a0f64c24e37f38d3fe217a58169d2fe6ed6d70554964042474023", size = 50689, upload-time = "2026-02-17T16:12:25.766Z" }, - { url = "https://files.pythonhosted.org/packages/a0/76/cd4d010ab2147339ca2b93e959c3686e964edc6de66ddacc935c325883d7/librt-0.8.1-cp314-cp314-win_amd64.whl", hash = "sha256:7e2f3edca35664499fbb36e4770650c4bd4a08abc1f4458eab9df4ec56389730", size = 57875, upload-time = "2026-02-17T16:12:27.465Z" }, - { url = "https://files.pythonhosted.org/packages/84/0f/2143cb3c3ca48bd3379dcd11817163ca50781927c4537345d608b5045998/librt-0.8.1-cp314-cp314-win_arm64.whl", hash = "sha256:0d2f82168e55ddefd27c01c654ce52379c0750ddc31ee86b4b266bcf4d65f2a3", size = 48058, upload-time = "2026-02-17T16:12:28.556Z" }, - { url = "https://files.pythonhosted.org/packages/d2/0e/9b23a87e37baf00311c3efe6b48d6b6c168c29902dfc3f04c338372fd7db/librt-0.8.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2c74a2da57a094bd48d03fa5d196da83d2815678385d2978657499063709abe1", size = 68313, upload-time = "2026-02-17T16:12:29.659Z" }, - { url = "https://files.pythonhosted.org/packages/db/9a/859c41e5a4f1c84200a7d2b92f586aa27133c8243b6cac9926f6e54d01b9/librt-0.8.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a355d99c4c0d8e5b770313b8b247411ed40949ca44e33e46a4789b9293a907ee", size = 70994, upload-time = "2026-02-17T16:12:31.516Z" }, - { url = "https://files.pythonhosted.org/packages/4c/28/10605366ee599ed34223ac2bf66404c6fb59399f47108215d16d5ad751a8/librt-0.8.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2eb345e8b33fb748227409c9f1233d4df354d6e54091f0e8fc53acdb2ffedeb7", size = 220770, upload-time = "2026-02-17T16:12:33.294Z" }, - { url = "https://files.pythonhosted.org/packages/af/8d/16ed8fd452dafae9c48d17a6bc1ee3e818fd40ef718d149a8eff2c9f4ea2/librt-0.8.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9be2f15e53ce4e83cc08adc29b26fb5978db62ef2a366fbdf716c8a6c8901040", size = 235409, upload-time = "2026-02-17T16:12:35.443Z" }, - { url = "https://files.pythonhosted.org/packages/89/1b/7bdf3e49349c134b25db816e4a3db6b94a47ac69d7d46b1e682c2c4949be/librt-0.8.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:785ae29c1f5c6e7c2cde2c7c0e148147f4503da3abc5d44d482068da5322fd9e", size = 246473, upload-time = "2026-02-17T16:12:36.656Z" }, - { url = "https://files.pythonhosted.org/packages/4e/8a/91fab8e4fd2a24930a17188c7af5380eb27b203d72101c9cc000dbdfd95a/librt-0.8.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1d3a7da44baf692f0c6aeb5b2a09c5e6fc7a703bca9ffa337ddd2e2da53f7732", size = 238866, upload-time = "2026-02-17T16:12:37.849Z" }, - { url = "https://files.pythonhosted.org/packages/b9/e0/c45a098843fc7c07e18a7f8a24ca8496aecbf7bdcd54980c6ca1aaa79a8e/librt-0.8.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5fc48998000cbc39ec0d5311312dda93ecf92b39aaf184c5e817d5d440b29624", size = 250248, upload-time = "2026-02-17T16:12:39.445Z" }, - { url = "https://files.pythonhosted.org/packages/82/30/07627de23036640c952cce0c1fe78972e77d7d2f8fd54fa5ef4554ff4a56/librt-0.8.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:e96baa6820280077a78244b2e06e416480ed859bbd8e5d641cf5742919d8beb4", size = 240629, upload-time = "2026-02-17T16:12:40.889Z" }, - { url = "https://files.pythonhosted.org/packages/fb/c1/55bfe1ee3542eba055616f9098eaf6eddb966efb0ca0f44eaa4aba327307/librt-0.8.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:31362dbfe297b23590530007062c32c6f6176f6099646bb2c95ab1b00a57c382", size = 239615, upload-time = "2026-02-17T16:12:42.446Z" }, - { url = "https://files.pythonhosted.org/packages/2b/39/191d3d28abc26c9099b19852e6c99f7f6d400b82fa5a4e80291bd3803e19/librt-0.8.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cc3656283d11540ab0ea01978378e73e10002145117055e03722417aeab30994", size = 263001, upload-time = "2026-02-17T16:12:43.627Z" }, - { url = "https://files.pythonhosted.org/packages/b9/eb/7697f60fbe7042ab4e88f4ee6af496b7f222fffb0a4e3593ef1f29f81652/librt-0.8.1-cp314-cp314t-win32.whl", hash = "sha256:738f08021b3142c2918c03692608baed43bc51144c29e35807682f8070ee2a3a", size = 51328, upload-time = "2026-02-17T16:12:45.148Z" }, - { url = "https://files.pythonhosted.org/packages/7c/72/34bf2eb7a15414a23e5e70ecb9440c1d3179f393d9349338a91e2781c0fb/librt-0.8.1-cp314-cp314t-win_amd64.whl", hash = "sha256:89815a22daf9c51884fb5dbe4f1ef65ee6a146e0b6a8df05f753e2e4a9359bf4", size = 58722, upload-time = "2026-02-17T16:12:46.85Z" }, - { url = "https://files.pythonhosted.org/packages/b2/c8/d148e041732d631fc76036f8b30fae4e77b027a1e95b7a84bb522481a940/librt-0.8.1-cp314-cp314t-win_arm64.whl", hash = "sha256:bf512a71a23504ed08103a13c941f763db13fb11177beb3d9244c98c29fb4a61", size = 48755, upload-time = "2026-02-17T16:12:47.943Z" }, +version = "0.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/36/9b/356320fbae2ac8467e21c5e73e1389c80468e4998c62cc7d3536cc51b614/librt-0.15.0.tar.gz", hash = "sha256:4e66cbe84437497d951b799d3e1551291b6fb3d643820a7014b3655d57a59162", size = 214338, upload-time = "2026-08-07T10:49:42.663Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/39/99c25030e782bdfb7a21be8c05254806a2e4bbb05c8d50c2a2130acbfa05/librt-0.15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e87bc679f86a99aa3b26e3c78eeb821a247c9a28eae48eaafcc32c3bf4c3bb9e", size = 151021, upload-time = "2026-08-07T10:47:00.057Z" }, + { url = "https://files.pythonhosted.org/packages/14/43/f4b1bd1b2888798a1409808889a25ea1ba49eaabce7d681ed27734c2df9d/librt-0.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:71599e011ac880e8e45d46047d714871894c7d4ab6f25626f8d4f89da21f368d", size = 155267, upload-time = "2026-08-07T10:47:01.311Z" }, + { url = "https://files.pythonhosted.org/packages/0c/db/3ad9c965c72f1e1d6beeec44ec10a54e17be8ae042fbb4baade16cbadced/librt-0.15.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c802434092b769b1d613ed2e13fac15fbfce1934a74bd10283b03c0fae231cd1", size = 503136, upload-time = "2026-08-07T10:47:02.45Z" }, + { url = "https://files.pythonhosted.org/packages/4b/07/5888a6d76acd62ebce66c61b74d94e9370b9c32929f111e487bb6546f8ed/librt-0.15.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:5500eeae393a184d14e1f35645962c27129d20c81afa4069e6ef826ebc2b3aaa", size = 496670, upload-time = "2026-08-07T10:47:03.675Z" }, + { url = "https://files.pythonhosted.org/packages/29/39/ab57cc2f5b276156da02bb7f5a8921bada1cb1993ffec99acf811c602c23/librt-0.15.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6ecfc32dfb46fb7b565bcd6abf9412acf978775a998273d22888a6d7953730dd", size = 513688, upload-time = "2026-08-07T10:47:04.981Z" }, + { url = "https://files.pythonhosted.org/packages/a7/b9/bdbb0b648b5c2befb031f4c6f3b1dd857415e8fb492a25a3c764a6681e6c/librt-0.15.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:89cc46cfd15022e35084355478c9ac809d90b1152222706ac9a7655ec21df6fa", size = 531904, upload-time = "2026-08-07T10:47:06.211Z" }, + { url = "https://files.pythonhosted.org/packages/93/26/473c2e4b6c104e9e58e27ce95fc8005c8bd4fc36cae4f254371125a92db8/librt-0.15.0-cp312-cp312-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d5f51401d102c885b9ca509e62c79b1dbff286e1b9b047fde6f763780789356d", size = 524427, upload-time = "2026-08-07T10:47:07.592Z" }, + { url = "https://files.pythonhosted.org/packages/26/60/03b3abb82b41714671b907bf6989b228e31e6a8af52dec82b5b0728dc250/librt-0.15.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cc30523e3f1a23fb7511cc659834a0d01a1042bb9de359bc1c131cc4ec6c9656", size = 543155, upload-time = "2026-08-07T10:47:08.866Z" }, + { url = "https://files.pythonhosted.org/packages/f2/0e/9bb1f0a4affbd0a1888f4f79dc03ed2a299d9a2c26c59ab2a97dcbf11903/librt-0.15.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:59fe030d8ae4a57e3fb7756bf35a858de74e04066fc8555c53d0af979132af81", size = 546890, upload-time = "2026-08-07T10:47:10.327Z" }, + { url = "https://files.pythonhosted.org/packages/dc/84/6937a280d461f7de6e031ffb02edc2b7c3c90d49d630565ce8ff27cbc5f2/librt-0.15.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5a6526a2a956bbb1e4ae3568c82e650fc99119c66bb011ea60715744955a2b4d", size = 555163, upload-time = "2026-08-07T10:47:11.798Z" }, + { url = "https://files.pythonhosted.org/packages/bc/95/2a2853c1ee014bf102116e7f897a04beeaeb2461b45b79af98bdfb95f1ef/librt-0.15.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:85ea21ec6730194d67156b0e0b5430ccb1d61f8b8b907e39b37f9812b74a13f0", size = 535812, upload-time = "2026-08-07T10:47:13.279Z" }, + { url = "https://files.pythonhosted.org/packages/c9/4c/cf9601c1b4c5f09280acd5d83abdb2e68527a2be8257136eb42304218622/librt-0.15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1e47b8ba865d7ede071a91a7163073bbaeb72541f1ef8a07d512c45c7b5007f2", size = 573688, upload-time = "2026-08-07T10:47:14.727Z" }, + { url = "https://files.pythonhosted.org/packages/47/6d/9ac7cbec46189a7625af4b5acbd25f10d827f4141b2002181848c8418923/librt-0.15.0-cp312-cp312-win32.whl", hash = "sha256:a5207ec414d1c4a2a7231b2086970dc036f94293cdf338190984958a013a42f1", size = 106138, upload-time = "2026-08-07T10:47:15.973Z" }, + { url = "https://files.pythonhosted.org/packages/38/d0/2ae99c83be86ce23f925ac1aeeedc777e97f427c4a8d190c70d0a16e9a87/librt-0.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:73b30cfa976659b3917c8f6153bdb0591c6a9ec6583599fd24a689b690622022", size = 126974, upload-time = "2026-08-07T10:47:17.049Z" }, + { url = "https://files.pythonhosted.org/packages/5d/ef/dd24f9635c730b86b87587967dda7516b1845e8b17684603d31607fed598/librt-0.15.0-cp312-cp312-win_arm64.whl", hash = "sha256:a54cf9e0ef47b96af580849db5471142200568ce1e02cbf416addab551369570", size = 112292, upload-time = "2026-08-07T10:47:18.222Z" }, + { url = "https://files.pythonhosted.org/packages/e7/42/467b53a601b406ccd7b97c1fd54b59cb34f9185ad5ce7e9d5c3c4e8961c8/librt-0.15.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:db13ca398005abcbe538deda87b686d9bd08b7001cf40c4c06b444960ae10a26", size = 151029, upload-time = "2026-08-07T10:47:19.312Z" }, + { url = "https://files.pythonhosted.org/packages/3e/e6/36c2299b7a94b84fdd01220d8a777a71be5be0925bb0dbdf71c0a06a34d9/librt-0.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:aa1f1995789dca3698bc550aaceb09a51bd5df0a057ff84ff15296cd1975b801", size = 155194, upload-time = "2026-08-07T10:47:20.398Z" }, + { url = "https://files.pythonhosted.org/packages/c9/b6/ed5071f9325845e670bd36012757419767fbf56af77ed483077b9e4db541/librt-0.15.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:55456ea87d8df21808446d03817be2f65e20391c1c615d9187440dff28cd08dc", size = 502568, upload-time = "2026-08-07T10:47:21.652Z" }, + { url = "https://files.pythonhosted.org/packages/7f/81/6450c67c3615d87704bcbc21323fafc69c799b06a044c447529f725d4b01/librt-0.15.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:5a86a5a08c2235316bdb359d5dbb6ce0abfca7fac06363103e2c5af571d92f95", size = 496153, upload-time = "2026-08-07T10:47:22.925Z" }, + { url = "https://files.pythonhosted.org/packages/e1/d6/5f52b722bc75076954b3bfd49be15ea362df4d580c6fb315d0f617100d30/librt-0.15.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e56b6a368529bed262da40ce13f8fef590db0479819cca84f16a1f01ac356d0b", size = 513336, upload-time = "2026-08-07T10:47:24.213Z" }, + { url = "https://files.pythonhosted.org/packages/8d/e2/c08fd1d36ce63ea5a12b85c5d37f4550b5f86a692167e41e5a74222607ae/librt-0.15.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:234d8d394721fa0d786af15ebf1f3fb7f3ed82fd1cd0cde45c2f247b5d4281d2", size = 531661, upload-time = "2026-08-07T10:47:25.507Z" }, + { url = "https://files.pythonhosted.org/packages/3f/d8/d9482fcbeb177b9eb87bb3899eeb3b42be690313c652f9e146b1d0681fb2/librt-0.15.0-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d8363d7accb0286ac3a0e633f396e93800dafb8150494505daf9515bbda591f3", size = 524487, upload-time = "2026-08-07T10:47:26.79Z" }, + { url = "https://files.pythonhosted.org/packages/10/cc/075171517b41f861753034fbb151b42cfc83bcc853849f24f5e66fd60ccf/librt-0.15.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0f0ee3644d951f31055ad07d77d92520e84505dd7a432cc4cd501dd70ee06785", size = 543201, upload-time = "2026-08-07T10:47:27.999Z" }, + { url = "https://files.pythonhosted.org/packages/b0/03/42c2330f37eeb475b6affeedd06518f60035f323af3a839335e3fc9fef2d/librt-0.15.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2cfd1a81a648806e6a7717be4cc4d1bb392fa229752bf8444ba365e381e984d6", size = 546467, upload-time = "2026-08-07T10:47:29.396Z" }, + { url = "https://files.pythonhosted.org/packages/57/1e/1ad4c5638f7e64d8560328bd25c54b409a661bdb6ff254b38ff90744288d/librt-0.15.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a6cd22c9da0d866558e46a041f1cc0c2bbb26b61b137b2347fa834c332e1d101", size = 555139, upload-time = "2026-08-07T10:47:30.815Z" }, + { url = "https://files.pythonhosted.org/packages/49/41/39fa7d15db1204cd1cbe6514680fbdc243adf754a0885061308f43afc013/librt-0.15.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:6d5225ef8801e4ea5e482fa9b5dfb891dd9ef6f6d870f1f25d449ca2c70ac218", size = 536050, upload-time = "2026-08-07T10:47:32.222Z" }, + { url = "https://files.pythonhosted.org/packages/1e/88/c6dcf0dd8e26dc0c9a499a2abab8646c86dcaf9ecea9524cb46d3686331a/librt-0.15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d28a05796b99f749bf8794f17ba9ba1612d0076b802e9cfc62c554634e9ce3b", size = 573700, upload-time = "2026-08-07T10:47:33.527Z" }, + { url = "https://files.pythonhosted.org/packages/1b/9b/ab54c71a7918a7c34fa5327fb61390a77446a07a146fbfb1165250a61035/librt-0.15.0-cp313-cp313-pyemscripten_2025_0_wasm32.whl", hash = "sha256:2067ff438048cead9d223ca5675bae2a25e520a7c3e6c1498bf9c6892d22caab", size = 82194, upload-time = "2026-08-07T10:47:34.835Z" }, + { url = "https://files.pythonhosted.org/packages/8d/b2/4f9a243bb892395f3becb80789ade13771701091f9f07ab8230247953ba8/librt-0.15.0-cp313-cp313-win32.whl", hash = "sha256:1cd3b721f24c206398b9e26da3c3a9c011e6e89d06f318ba8ebefc30f1003890", size = 106231, upload-time = "2026-08-07T10:47:36.251Z" }, + { url = "https://files.pythonhosted.org/packages/bf/af/64aff4885a40b93132382f2c314647d722574605416504379184ef3045ea/librt-0.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:f395a4a9a03ac062dbe9a9f82e0c720502e590a38feee6a757bc82e9c63afbd8", size = 126996, upload-time = "2026-08-07T10:47:37.453Z" }, + { url = "https://files.pythonhosted.org/packages/27/83/335bccf6c7cb9028cb0b54aead27d9ece3f01f83bc6baa2abace5da655c1/librt-0.15.0-cp313-cp313-win_arm64.whl", hash = "sha256:0a15cb554761247d84a3ec0cbdf4078d70725384f0e4662c0fa3b26266eb60ad", size = 112188, upload-time = "2026-08-07T10:47:38.729Z" }, + { url = "https://files.pythonhosted.org/packages/a8/93/949053fb462eecc4a9a5ee770a81f4b40be7b79538b245545d4aebc6b58b/librt-0.15.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:f5de7feedc56337a088eb15cd9fafa9938367362221d8cc62c642b7f94821993", size = 149833, upload-time = "2026-08-07T10:47:39.86Z" }, + { url = "https://files.pythonhosted.org/packages/61/ca/8281aa6cd560a3420e4497729f6b704b53be3eeaaef82d5aeadddaf7441f/librt-0.15.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6c0eb900c0e91f4aebe680845242e614f1864edfd44106380d0752ac29522bf8", size = 154088, upload-time = "2026-08-07T10:47:41.065Z" }, + { url = "https://files.pythonhosted.org/packages/dd/02/1a1662dceaba6a086360891448d5ce9a7d3555976cae59a31a39d744b9c7/librt-0.15.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e8c9a650a188e38bac005048cbe6342e81407782944d01934540ab75e417df21", size = 494215, upload-time = "2026-08-07T10:47:42.388Z" }, + { url = "https://files.pythonhosted.org/packages/69/84/99211619dc656370a3740c33d2b0b6d5a3fb1e73689314f6ed477a397dc4/librt-0.15.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:92bfed8deec93df30286b9fe9e3b1dd17329cc076a192b4ee5ec223841d54953", size = 491173, upload-time = "2026-08-07T10:47:43.683Z" }, + { url = "https://files.pythonhosted.org/packages/d4/aa/5448d0b05f4579b635d3899176817ebf561af0e57bacd425b5b1887264c1/librt-0.15.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ec4b19788f835711a2072f9dbe6b03b3bf32ed1f0fb30cf399bdd59d9f0c33fa", size = 505512, upload-time = "2026-08-07T10:47:45.314Z" }, + { url = "https://files.pythonhosted.org/packages/95/82/01940e40b83c43a546c4a3c896cf34ca272a9690899d55914e4827b3dcce/librt-0.15.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d4c7bacb70930f3d0a56f4ecf1be474a1f0d941b01dd73b756f3c256d42cb879", size = 523073, upload-time = "2026-08-07T10:47:46.66Z" }, + { url = "https://files.pythonhosted.org/packages/88/fa/759c0030f3ee371439eb26de34fc745807caf0abb878af7af4b8b7c3dd3d/librt-0.15.0-cp314-cp314-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3e79f05e4a08b4d880342673312bbc895b56df7765605796f15902eb5367d3ae", size = 515080, upload-time = "2026-08-07T10:47:48.319Z" }, + { url = "https://files.pythonhosted.org/packages/0b/27/894e072228fcb159703c655da69f8cd10dbed489c36e3df7dd032a2483be/librt-0.15.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a417149c0cba4d50b61e992e5a15e69eaf96746609b461cc4ed168aeef6b79dd", size = 534164, upload-time = "2026-08-07T10:47:49.875Z" }, + { url = "https://files.pythonhosted.org/packages/98/a3/0078e91c1f36f8815db17827de15650b9a3fe56c55fbf998c854b34e40d3/librt-0.15.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:da7a94d6a3411f579d72aa3e3bc5fbca7ed4549f3dbd7e5de3aa567333374285", size = 540616, upload-time = "2026-08-07T10:47:51.408Z" }, + { url = "https://files.pythonhosted.org/packages/86/33/81a29b796dd52a45e9ef7974c7732926e8f10f15b8d2be505665979f896d/librt-0.15.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:856f743ae607f2c1380eccb566c0038a9fb3eabf0fc2be2704d76d9f73557239", size = 545890, upload-time = "2026-08-07T10:47:52.818Z" }, + { url = "https://files.pythonhosted.org/packages/05/82/8be1baa1350e5d30cfd70ae79d0a6f4dc5862ef47f7bb2808aabc9bb86e5/librt-0.15.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:779a6e7c894737e5983e7790a9c78c4000c30e23c9aada08081bdbea53b0fa60", size = 523287, upload-time = "2026-08-07T10:47:54.165Z" }, + { url = "https://files.pythonhosted.org/packages/c6/4f/d1be6a01a35c20ef734e0e44113f87d4af756a9354a89dcfbe3b4f8af5e1/librt-0.15.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:96bb17dbe8bab3c0954fbebfc69ed395599de75b6bbc35e3270a878e15d4dd65", size = 565868, upload-time = "2026-08-07T10:47:55.566Z" }, + { url = "https://files.pythonhosted.org/packages/67/88/649cfa33f5825927b160610f670bdab012a64d627eddb94fa795ea4292fd/librt-0.15.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:7220697efaa6e5348fc3d18ee7f8563d4bfecd9872b37ffb915bfc1d08840622", size = 81619, upload-time = "2026-08-07T10:47:56.886Z" }, + { url = "https://files.pythonhosted.org/packages/22/31/8e88a8d5e48fc8d1a817787fb6811dfff6499acd6c8683dd83934aa6ede0/librt-0.15.0-cp314-cp314-win32.whl", hash = "sha256:f54598964d357b1c5ab77cf5d92f21e598fe0e23cdbe9618480807f81b4eba15", size = 100138, upload-time = "2026-08-07T10:47:58.093Z" }, + { url = "https://files.pythonhosted.org/packages/80/92/20fd6c4b6a1b1a564b076d55cd3d427d8428217d7638dc25a654cc4791d4/librt-0.15.0-cp314-cp314-win_amd64.whl", hash = "sha256:3ff5893a2c23d886aa9ce786de5ac6ddc74aeeaf90743682b74d920e117d2e28", size = 121258, upload-time = "2026-08-07T10:47:59.564Z" }, + { url = "https://files.pythonhosted.org/packages/fc/28/6af430b44d9ebb897b865a3c363b6dcace51357be2347cc0f8f869656a86/librt-0.15.0-cp314-cp314-win_arm64.whl", hash = "sha256:3722a099730704c9a3d70c879fc0f51daec25fe5f1555672d97bc595abeafb95", size = 106467, upload-time = "2026-08-07T10:48:01.097Z" }, + { url = "https://files.pythonhosted.org/packages/7e/aa/b42bb798942ced219f6d63b27e07f91237887a8d0bd0921666db79a13790/librt-0.15.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:38c0c7d4b6fc06c3324b3f9162c8391bfc4fd9dde53afe1033ce7edb48d5a714", size = 159523, upload-time = "2026-08-07T10:48:02.442Z" }, + { url = "https://files.pythonhosted.org/packages/75/03/1b53cd4ef904e73b1d828a5f90143bf94a2967d7cfff0b9ccf93e12aa9b4/librt-0.15.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8b2fdd7ead3c995c37940a790690660d0ca006c302db26cc51933f6766866fc3", size = 161638, upload-time = "2026-08-07T10:48:03.725Z" }, + { url = "https://files.pythonhosted.org/packages/ac/c4/9f9c9fba097d49e9e694c2b4dc331df31884645ecbc58a93b4b5fc69d2c5/librt-0.15.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2fde98cf1fc4bac144ce23c2c4c017b924ba714509ea9334977b0b27050c837d", size = 701795, upload-time = "2026-08-07T10:48:05.135Z" }, + { url = "https://files.pythonhosted.org/packages/4c/05/0966840bda0380c8ae167b9043c6230202941cc90ea29c48e096964c765e/librt-0.15.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:e3b461183c5fa7681b48560f91515f53a953122fb30c71e07abc67d7ddf58c38", size = 682147, upload-time = "2026-08-07T10:48:06.555Z" }, + { url = "https://files.pythonhosted.org/packages/18/af/1c47ca573c30ea47d195aec26133af522fea1104afaace028d7b32247ea8/librt-0.15.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4bbcc257e3babea20a91715c361b24554ec4e8f51aa578568afc230799fe1a19", size = 696397, upload-time = "2026-08-07T10:48:08.03Z" }, + { url = "https://files.pythonhosted.org/packages/2e/0f/1aed6223d4f9f9d1171a8596ff100ea4c3f7699fea7a4ba657c3e60daa6c/librt-0.15.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b845b8d48088fad0cadc84be4b8fda63203be7e9237b71015b3925443c1f35ab", size = 722542, upload-time = "2026-08-07T10:48:09.569Z" }, + { url = "https://files.pythonhosted.org/packages/c6/22/9e3a929aea456c97d69e6ef3884efea56d4807f97399471cc946baebd8af/librt-0.15.0-cp314-cp314t-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b30e600e8f337b9bd7f39b86d9fdfedc73cc46e3d0f745931a23a234220bb7e2", size = 729709, upload-time = "2026-08-07T10:48:11.129Z" }, + { url = "https://files.pythonhosted.org/packages/e9/1b/c327ef6018e3a9ca0b8e7c5eddeeb331ba8f9b76c24e126d37d0f6d62faf/librt-0.15.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:64b0c8c35aa4c4ed79896359f3e0b285cbe4e610042106500da4811c322cc108", size = 752891, upload-time = "2026-08-07T10:48:12.558Z" }, + { url = "https://files.pythonhosted.org/packages/d7/d1/d5f1ea02c56930087009e39db9b70660a663e76c730b27b925d786718457/librt-0.15.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:0da0d94cb802f32a0524653e7201f2cef72d5f700a5407678f5290483d4fcd08", size = 745301, upload-time = "2026-08-07T10:48:14.55Z" }, + { url = "https://files.pythonhosted.org/packages/d9/3c/5f7c585d15ebb2250c73e7c0ee4e9e47be72c65d520c07ddbcdc62037674/librt-0.15.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:4a6369168d371207339b1e50d4532b06a7121586141f82599505a3f315751d47", size = 747921, upload-time = "2026-08-07T10:48:16.453Z" }, + { url = "https://files.pythonhosted.org/packages/7f/52/1443a446486eba966bcbca1696b472e4f210320ec42f490a47f48fbf0fdc/librt-0.15.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:c434e072557ade9cbc642d052c89d031efe47d5c9614523619d0d74a02378e81", size = 727561, upload-time = "2026-08-07T10:48:18.089Z" }, + { url = "https://files.pythonhosted.org/packages/79/91/2270a9380f11725cf83ce1925a5e32dd1dde2be9bba597f25c10a38644e7/librt-0.15.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c7eec6a42018bc1d45763b1c162d3d2bf7c3b9a1b0ed30d3e91dcba390efefcc", size = 774417, upload-time = "2026-08-07T10:48:19.611Z" }, + { url = "https://files.pythonhosted.org/packages/9e/3b/f4b1548d4f5b99186737fe27aec238e9823e8d5d23bf4df007c030689dc5/librt-0.15.0-cp314-cp314t-win32.whl", hash = "sha256:6912fa5e635d74529ac7cdb1bdf6ca3af4453da8d1edbe0110ee1cb4ad407ebf", size = 104381, upload-time = "2026-08-07T10:48:21.048Z" }, + { url = "https://files.pythonhosted.org/packages/80/b6/134afad262def1de04c0843c376d02135f1168af43f22e09a52bd8394727/librt-0.15.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8e11699ed745931c395acd3621b07062e0f840efa6935aad87a64ed0995f0915", size = 127034, upload-time = "2026-08-07T10:48:22.561Z" }, + { url = "https://files.pythonhosted.org/packages/99/5f/1b6846b20572bd699c9e9ec321a5f781845bee477df2aa2a43b28bc40119/librt-0.15.0-cp314-cp314t-win_arm64.whl", hash = "sha256:5d2a91724463bfed4f573cd7a9fdc856d2e230d0c0e5a61416a93481dccd8605", size = 110827, upload-time = "2026-08-07T10:48:23.804Z" }, + { url = "https://files.pythonhosted.org/packages/c6/44/4de9f4ddadb009a55c7758eb5736d62534a7daaf27bd71bc50e64b606b06/librt-0.15.0-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:8443e38dcfcfdbcf5add5118c623efd788d65ac2e25756d6251a54a06a4d0aca", size = 149843, upload-time = "2026-08-07T10:48:25.148Z" }, + { url = "https://files.pythonhosted.org/packages/1f/eb/5d9ab71e30119c44094e0275f38b47dd327aea0f843a080396677029d508/librt-0.15.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:6d15a29033c57490cfe2069097c6fc4049e4e65ffbb749be7dc453b7c4c68965", size = 154510, upload-time = "2026-08-07T10:48:26.485Z" }, + { url = "https://files.pythonhosted.org/packages/d0/9c/8505d1b8f5e8c19587bd03f7429993b3e9ce5c06819d856bfb11d919374c/librt-0.15.0-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d2c05c729b589e734c09578bf5964be48a911765484840d017bbc84f49d4c4ad", size = 497543, upload-time = "2026-08-07T10:48:28.045Z" }, + { url = "https://files.pythonhosted.org/packages/1d/9a/3a8390775cb095765aded027ac9c63e7c8ea74e731498607544c6505de0e/librt-0.15.0-cp315-cp315-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:fa60887537e1d0cd2d9982269d33a709bf54b195cd2b9364fc0a758022af5bd9", size = 480452, upload-time = "2026-08-07T10:48:29.531Z" }, + { url = "https://files.pythonhosted.org/packages/e7/40/258a4a7117ee915d66de5cd9b8ade65a440993161107ce3a686f1859955c/librt-0.15.0-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d8bc24219b24c0af375718942ab75e3544b2763085f40f965be4326734ae8328", size = 507768, upload-time = "2026-08-07T10:48:31.007Z" }, + { url = "https://files.pythonhosted.org/packages/6b/c6/2f4dd296c97a0b85b98894519b279408ec9dd602d4f692b1ea0e25dee670/librt-0.15.0-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:86a21a7bd3fe3a419512ef424cc1c020f6771d0b29cfddff36d1635a855e63f0", size = 525122, upload-time = "2026-08-07T10:48:32.7Z" }, + { url = "https://files.pythonhosted.org/packages/49/dd/29eab42be13b2bf0ea8cb227135a45d44693e30a7e8b92871981ff56b82b/librt-0.15.0-cp315-cp315-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:dbab647e88d90b3167b91efe7091e248653688ed4337e4f90907a722c7361bb9", size = 520371, upload-time = "2026-08-07T10:48:34.294Z" }, + { url = "https://files.pythonhosted.org/packages/91/ed/4bad71adeca8fe208b775c2a35417fa5a2584c8f4791daaf89a89450fea1/librt-0.15.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:d8edcf6f550e918dca779c069b9e156385c60b406f99fc7641f32c52f7193659", size = 537258, upload-time = "2026-08-07T10:48:35.88Z" }, + { url = "https://files.pythonhosted.org/packages/4c/63/59dba6143fdcc7240c54458b629f3250000a61b8945890fc9efd451b19c5/librt-0.15.0-cp315-cp315-musllinux_1_2_i686.whl", hash = "sha256:8b62076030baa2d8b1501a46bf0e19c27a489aa90671c55665bff7887f7660b0", size = 527432, upload-time = "2026-08-07T10:48:37.466Z" }, + { url = "https://files.pythonhosted.org/packages/ec/21/21a24c6a2327d8362580efebe77286bf47b0f4062ec5ea41766e609d3c7d/librt-0.15.0-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:d00d20d1818e82a07a0ee0aa89a98b17ed7916b92441090b683719cb20a59b6d", size = 548108, upload-time = "2026-08-07T10:48:39.384Z" }, + { url = "https://files.pythonhosted.org/packages/5a/6d/fc68c89a7971418b41f9a873623ff935cb864097544c6a2f8ce491c8ef5d/librt-0.15.0-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:4e6ee93fc3cf848dcbf0cce2eca73d8e7dcd0cc2b6df3a529d57750b30a4c55c", size = 529681, upload-time = "2026-08-07T10:48:41.392Z" }, + { url = "https://files.pythonhosted.org/packages/65/7e/c2d98766124400d722063a630b0fde38a9fc768705d37eecca15c47dc192/librt-0.15.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:32896a0af72508ea979e0acb4e4c04cbeeae04938167950d535c83c45597167d", size = 567736, upload-time = "2026-08-07T10:48:43.124Z" }, + { url = "https://files.pythonhosted.org/packages/55/6c/f8c34a95e3a515c6e1c192b89511e7253c89a7760c6b500d57ffdb8d2dc8/librt-0.15.0-cp315-cp315-pyemscripten_2026_5_wasm32.whl", hash = "sha256:ec3ba415afaf951f6951b1dd16d3c8e4f540065fc382d7e70b823a79567ca374", size = 81673, upload-time = "2026-08-07T10:48:44.645Z" }, + { url = "https://files.pythonhosted.org/packages/c9/9e/e23fa8e78679ec45728188650b39e8ff476c83b691c96f749217df3b1b7c/librt-0.15.0-cp315-cp315-win32.whl", hash = "sha256:d2813ba2503764f0450680c533d13df7cff9b49df1411062eded5f67db4195b9", size = 100081, upload-time = "2026-08-07T10:48:46.171Z" }, + { url = "https://files.pythonhosted.org/packages/e1/dc/3eb4c5e297343f0620a55532cd7c8d764d3001fa2159212dadf480464827/librt-0.15.0-cp315-cp315-win_amd64.whl", hash = "sha256:b87d67e33afaf265262f2a66db578284b88ee2e6fcd224579cb5c15518677ad8", size = 121228, upload-time = "2026-08-07T10:48:47.631Z" }, + { url = "https://files.pythonhosted.org/packages/97/70/43abce19f04e49762f8ec834c8fafee13cc40fd6b94a72a24e534febfcd0/librt-0.15.0-cp315-cp315-win_arm64.whl", hash = "sha256:713bd7df21170b982e729e46870f31d6b437bd1a9b4648cffb529bd3c2ec5c4b", size = 106487, upload-time = "2026-08-07T10:48:49.095Z" }, + { url = "https://files.pythonhosted.org/packages/de/15/83f2deddb9368b8951ec8c9477269b5b9b8bd9bbf15e57402d0f38817dca/librt-0.15.0-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:3de789c82752730f94782a5ee518baf9c05edf85733aeaf73bb6e518755cdf54", size = 159448, upload-time = "2026-08-07T10:48:50.649Z" }, + { url = "https://files.pythonhosted.org/packages/06/bf/043097353f9b3c73b583d07f6b8e552795463f4bfc8caf85e42eee50c26a/librt-0.15.0-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:e0b5deec9a8664eb722c797241970fd4aa1894d25fda36a1ddac0f7407606bd6", size = 161686, upload-time = "2026-08-07T10:48:52.174Z" }, + { url = "https://files.pythonhosted.org/packages/f4/2a/8ae77f9719d42ce71cd708560a3557b38ac3c17a0383e57f87084de45bbe/librt-0.15.0-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5563302a8359bc2295bb7084d1a8ed1519df96afb30eb2aa4e0bff7b54228988", size = 710668, upload-time = "2026-08-07T10:48:53.782Z" }, + { url = "https://files.pythonhosted.org/packages/61/34/c0436ea134deb9a0d6da80a396a2739a81cb31e0418f7227239e23140898/librt-0.15.0-cp315-cp315t-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:22d6263b9d39d7bbb286fa791945646e3218f1be2d693e36fb630f1d0e59cd13", size = 679396, upload-time = "2026-08-07T10:48:55.645Z" }, + { url = "https://files.pythonhosted.org/packages/4a/9f/001e0d99aa9250d5cd5715a9081291a20656083459f9019cda15255329e1/librt-0.15.0-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:39ffd14646190c454f0d86e0d256b33f00a87a26ab410e619773b841d0e41416", size = 704313, upload-time = "2026-08-07T10:48:57.46Z" }, + { url = "https://files.pythonhosted.org/packages/2d/53/b34fa9d0ff00f136f4d58ebb4c411ff634baed1eb412bb602a2bc8dcafcb/librt-0.15.0-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c47318cd3a61401452de11282242937e3e057c4fd3dbaf601e269d0928a06c0a", size = 729847, upload-time = "2026-08-07T10:48:59.231Z" }, + { url = "https://files.pythonhosted.org/packages/86/ac/fa4d7a424665040e95baf480a6d523446057684b6758624c85338e8a23b2/librt-0.15.0-cp315-cp315t-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a56a1d4f859a82ca5b99fc4b82c9b027b15e3c455c5cd99e7d0719f27bb20b6c", size = 742736, upload-time = "2026-08-07T10:49:01.151Z" }, + { url = "https://files.pythonhosted.org/packages/8a/f1/e17a9bb5de6fb8c3186ed1a7d68d21618b027ac2d3633e03d3b6109c67ae/librt-0.15.0-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:077471b3182db4e17c36ae91555f36a4d2c00080b267f749bcad34a478a9a302", size = 763454, upload-time = "2026-08-07T10:49:03.039Z" }, + { url = "https://files.pythonhosted.org/packages/1d/ec/ecd02cd30935b931b9cdbfed6ab5a099c51b280b4e7baa274da80978ed27/librt-0.15.0-cp315-cp315t-musllinux_1_2_i686.whl", hash = "sha256:411ca4d1b905b860ceba7570dd6717a71dedaddcc4b0f77ece710aa41ee11f8d", size = 743296, upload-time = "2026-08-07T10:49:04.941Z" }, + { url = "https://files.pythonhosted.org/packages/e6/b5/b3c2b8353ce820a4854f78d19321344242f89fa71c975b71132ba9bf242a/librt-0.15.0-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:1256589e0b0adb31751d685a68bce29d73407ddf4ef05d4188f49d5dcf9566d9", size = 756217, upload-time = "2026-08-07T10:49:06.825Z" }, + { url = "https://files.pythonhosted.org/packages/3c/52/6cc22542ba59146b05cca2a656f9ff8bb67e38e63d12c3b0cc183d837bf1/librt-0.15.0-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:f42b74a53e5f26a0ba0007411a7455b66c67ce4022a39cc1f56fc4efd65bcbab", size = 741934, upload-time = "2026-08-07T10:49:08.839Z" }, + { url = "https://files.pythonhosted.org/packages/40/32/a04b72b1aa86e3be23b2ecff8c1aad2dcc955bd3956d6d26e7e34267e57a/librt-0.15.0-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:291bf73caf78b9e88d6fae9bfd693207ff7d832e2fdbe2cf8e746bc13f5f892b", size = 783763, upload-time = "2026-08-07T10:49:10.661Z" }, + { url = "https://files.pythonhosted.org/packages/6c/f0/89eb11dffbe9279ff37144dec786927314502ae0b114f1449dc78c458aab/librt-0.15.0-cp315-cp315t-win32.whl", hash = "sha256:c16d15ee371643ab48dc8248a3e680ebbeca573a13af2c3dd0c985b142d77162", size = 104313, upload-time = "2026-08-07T10:49:12.305Z" }, + { url = "https://files.pythonhosted.org/packages/6d/4a/1f1978c200f563beda63c36adff2d65bbecb81e365e8e69e572f5f70fbc6/librt-0.15.0-cp315-cp315t-win_amd64.whl", hash = "sha256:dbd605739f228912dc49027cb764456b9757750bdc2b6b7773164db7096c6fd1", size = 126889, upload-time = "2026-08-07T10:49:13.881Z" }, + { url = "https://files.pythonhosted.org/packages/38/a6/800800bfed7b1fb10fc3f3d557785c3854e80d3f7a9800d784b176a1fc2d/librt-0.15.0-cp315-cp315t-win_arm64.whl", hash = "sha256:84d244b00604d17df3fc7736c327892d6bba66181254aa4087be807b6c342bdc", size = 110700, upload-time = "2026-08-07T10:49:15.499Z" }, ] [[package]] @@ -2492,11 +2601,11 @@ wheels = [ [[package]] name = "mistune" -version = "3.3.0" +version = "3.3.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/84/9c/1939635275ec7258e2b43b00dafabc36d89ad11aa7838d375dc1b0e561cb/mistune-3.3.0.tar.gz", hash = "sha256:3074ec4c61b384abe725128e4dcbb483f5a09cc4632012505cdee655d3a113b9", size = 110936, upload-time = "2026-06-21T13:11:39.458Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7b/a5/2dab368d6950e6808904dec98f54c7e726ee7be4a0c6afe00e6e011bd52d/mistune-3.3.3.tar.gz", hash = "sha256:c4c6c0c840b8637a2e9b8b6d607eb7c8f00888bf14c754409bcd339e848c2477", size = 115363, upload-time = "2026-07-09T06:18:05.268Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/76/b90f9d48d43fbd80a79a20d3eab2e5109859c7a56dc663b23187385898f3/mistune-3.3.0-py3-none-any.whl", hash = "sha256:a758e578acda49d8195f9a860b132dae2cf7bf409381393b1c4e6e489a65397b", size = 61250, upload-time = "2026-06-21T13:11:37.938Z" }, + { url = "https://files.pythonhosted.org/packages/89/70/b1e4737b84163db5bb1dfde6f216dbfbf32783330a9989c965e121172830/mistune-3.3.3-py3-none-any.whl", hash = "sha256:99de1585e42dcbd826faa9e11a202727a5e202e4e4722a4c69ac1ff615793dd7", size = 63569, upload-time = "2026-07-09T06:18:03.839Z" }, ] [[package]] @@ -2596,7 +2705,7 @@ wheels = [ [[package]] name = "mkdocs-material" -version = "9.7.6" +version = "9.7.7" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "babel" }, @@ -2611,9 +2720,9 @@ dependencies = [ { name = "pymdown-extensions" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/45/29/6d2bcf41ae40802c4beda2432396fff97b8456fb496371d1bc7aad6512ec/mkdocs_material-9.7.6.tar.gz", hash = "sha256:00bdde50574f776d328b1862fe65daeaf581ec309bd150f7bff345a098c64a69", size = 4097959, upload-time = "2026-03-19T15:41:58.161Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/cd/c05d3a530ba7934f144fb45f7203cd236adc25c7bdcc34673d202f4b0278/mkdocs_material-9.7.7.tar.gz", hash = "sha256:c0649c065b1b0512d60aad8c10f947f8e455284475239b364b610f2deb4d0855", size = 4097923, upload-time = "2026-07-17T16:21:33.156Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/01/bc663630c510822c95c47a66af9fa7a443c295b47d5f041e5e6ae62ef659/mkdocs_material-9.7.6-py3-none-any.whl", hash = "sha256:71b84353921b8ea1ba84fe11c50912cc512da8fe0881038fcc9a0761c0e635ba", size = 9305470, upload-time = "2026-03-19T15:41:55.217Z" }, + { url = "https://files.pythonhosted.org/packages/ad/21/17c1bc9e6f47c972ad66fb2ac2568f99f90f1207eeb6fc3b34d094dba7b5/mkdocs_material-9.7.7-py3-none-any.whl", hash = "sha256:8ea9bb1737a5b524a5f9dcf2e1b4ebda8274ae3008aa7845720a97083bef708f", size = 9305438, upload-time = "2026-07-17T16:21:30.017Z" }, ] [[package]] @@ -2702,45 +2811,56 @@ wheels = [ [[package]] name = "mypy" -version = "1.20.2" +version = "2.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ + { name = "ast-serialize" }, { name = "librt", marker = "platform_python_implementation != 'PyPy'" }, { name = "mypy-extensions" }, { name = "pathspec" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/04/af/e3d4b3e9ec91a0ff9aabfdb38692952acf49bbb899c2e4c29acb3a6da3ae/mypy-1.20.2.tar.gz", hash = "sha256:e8222c26daaafd9e8626dec58ae36029f82585890589576f769a650dd20fd665", size = 3817349, upload-time = "2026-04-21T17:12:28.473Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/71/4e/7560e4528db9e9b147e4c0f22660466bf30a0a1fe3d63d1b9d3b0fd354ee/mypy-1.20.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4dbfcf869f6b0517f70cf0030ba6ea1d6645e132337a7d5204a18d8d5636c02b", size = 14539393, upload-time = "2026-04-21T17:07:12.52Z" }, - { url = "https://files.pythonhosted.org/packages/32/d9/34a5efed8124f5a9234f55ac6a4ced4201e2c5b81e1109c49ad23190ec8c/mypy-1.20.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4b6481b228d072315b053210b01ac320e1be243dc17f9e5887ef167f23f5fae4", size = 13361642, upload-time = "2026-04-21T17:06:53.742Z" }, - { url = "https://files.pythonhosted.org/packages/d1/14/eb377acf78c03c92d566a1510cda8137348215b5335085ef662ab82ecd3a/mypy-1.20.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:34397cdced6b90b836e38182076049fdb41424322e0b0728c946b0939ebdf9f6", size = 13740347, upload-time = "2026-04-21T17:12:04.73Z" }, - { url = "https://files.pythonhosted.org/packages/b9/94/7e4634a32b641aa1c112422eed1bbece61ee16205f674190e8b536f884de/mypy-1.20.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a5da6976f20cae27059ea8d0c86e7cef3de720e04c4bb9ee18e3690fdb792066", size = 14734042, upload-time = "2026-04-21T17:07:43.16Z" }, - { url = "https://files.pythonhosted.org/packages/7a/f3/f7e62395cb7f434541b4491a01149a4439e28ace4c0c632bbf5431e92d1f/mypy-1.20.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:56908d7e08318d39f85b1f0c6cfd47b0cac1a130da677630dac0de3e0623e102", size = 14964958, upload-time = "2026-04-21T17:11:00.665Z" }, - { url = "https://files.pythonhosted.org/packages/3e/0d/47e3c3a0ec2a876e35aeac365df3cac7776c36bbd4ed18cc521e1b9d255b/mypy-1.20.2-cp312-cp312-win_amd64.whl", hash = "sha256:d52ad8d78522da1d308789df651ee5379088e77c76cb1994858d40a426b343b9", size = 10911340, upload-time = "2026-04-21T17:10:49.179Z" }, - { url = "https://files.pythonhosted.org/packages/d6/b2/6c852d72e0ea8b01f49da817fb52539993cde327e7d010e0103dc12d0dac/mypy-1.20.2-cp312-cp312-win_arm64.whl", hash = "sha256:785b08db19c9f214dc37d65f7c165d19a30fcecb48abfa30f31b01b5acaabb58", size = 9833947, upload-time = "2026-04-21T17:09:05.267Z" }, - { url = "https://files.pythonhosted.org/packages/5b/c4/b93812d3a192c9bcf5df405bd2f30277cd0e48106a14d1023c7f6ed6e39b/mypy-1.20.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:edfbfca868cdd6bd8d974a60f8a3682f5565d3f5c99b327640cedd24c4264026", size = 14524670, upload-time = "2026-04-21T17:10:30.737Z" }, - { url = "https://files.pythonhosted.org/packages/f3/47/42c122501bff18eaf1e8f457f5c017933452d8acdc52918a9f59f6812955/mypy-1.20.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e2877a02380adfcdbc69071a0f74d6e9dbbf593c0dc9d174e1f223ffd5281943", size = 13336218, upload-time = "2026-04-21T17:08:44.069Z" }, - { url = "https://files.pythonhosted.org/packages/92/8f/75bbc92f41725fbd585fb17b440b1119b576105df1013622983e18640a93/mypy-1.20.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7488448de6007cd5177c6cea0517ac33b4c0f5ee9b5e9f2be51ce75511a85517", size = 13724906, upload-time = "2026-04-21T17:08:01.02Z" }, - { url = "https://files.pythonhosted.org/packages/a1/32/4c49da27a606167391ff0c39aa955707a00edc500572e562f7c36c08a71f/mypy-1.20.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bb9c2fa06887e21d6a3a868762acb82aec34e2c6fd0174064f27c93ede68ad15", size = 14726046, upload-time = "2026-04-21T17:11:22.354Z" }, - { url = "https://files.pythonhosted.org/packages/7f/fc/4e354a1bd70216359deb0c9c54847ee6b32ef78dfb09f5131ff99b494078/mypy-1.20.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9d56a78b646f2e3daa865bc70cd5ec5a46c50045801ca8ff17a0c43abc97e3ee", size = 14955587, upload-time = "2026-04-21T17:12:16.033Z" }, - { url = "https://files.pythonhosted.org/packages/62/b2/c0f2056e9eb8f08c62cafd9715e4584b89132bdc832fcf85d27d07b5f3e5/mypy-1.20.2-cp313-cp313-win_amd64.whl", hash = "sha256:2a4102b03bb7481d9a91a6da8d174740c9c8c4401024684b9ca3b7cc5e49852f", size = 10922681, upload-time = "2026-04-21T17:06:35.842Z" }, - { url = "https://files.pythonhosted.org/packages/e5/14/065e333721f05de8ef683d0aa804c23026bcc287446b61cac657b902ccac/mypy-1.20.2-cp313-cp313-win_arm64.whl", hash = "sha256:a95a9248b0c6fd933a442c03c3b113c3b61320086b88e2c444676d3fd1ca3330", size = 9830560, upload-time = "2026-04-21T17:07:51.023Z" }, - { url = "https://files.pythonhosted.org/packages/ae/d1/b4ec96b0ecc620a4443570c6e95c867903428cfcde4206518eafdd5880c3/mypy-1.20.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:419413398fe250aae057fd2fe50166b61077083c9b82754c341cf4fd73038f30", size = 14524561, upload-time = "2026-04-21T17:06:27.325Z" }, - { url = "https://files.pythonhosted.org/packages/3a/63/d2c2ff4fa66bc49477d32dfa26e8a167ba803ea6a69c5efb416036909d30/mypy-1.20.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e73c07f23009962885c197ccb9b41356a30cc0e5a1d0c2ea8fd8fb1362d7f924", size = 13363883, upload-time = "2026-04-21T17:11:11.239Z" }, - { url = "https://files.pythonhosted.org/packages/2a/56/983916806bf4eddeaaa2c9230903c3669c6718552a921154e1c5182c701f/mypy-1.20.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c64e5973df366b747646fc98da921f9d6eba9716d57d1db94a83c026a08e0fb", size = 13742945, upload-time = "2026-04-21T17:08:34.181Z" }, - { url = "https://files.pythonhosted.org/packages/19/65/0cd9285ab010ee8214c83d67c6b49417c40d86ce46f1aa109457b5a9b8d7/mypy-1.20.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a65aa591af023864fd08a97da9974e919452cfe19cb146c8a5dc692626445dc", size = 14706163, upload-time = "2026-04-21T17:05:15.51Z" }, - { url = "https://files.pythonhosted.org/packages/94/97/48ff3b297cafcc94d185243a9190836fb1b01c1b0918fff64e941e973cc9/mypy-1.20.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4fef51b01e638974a6e69885687e9bd40c8d1e09a6cd291cca0619625cf1f558", size = 14938677, upload-time = "2026-04-21T17:05:39.562Z" }, - { url = "https://files.pythonhosted.org/packages/fd/a1/1b4233d255bdd0b38a1f284feeb1c143ca508c19184964e22f8d837ec851/mypy-1.20.2-cp314-cp314-win_amd64.whl", hash = "sha256:913485a03f1bcf5d279409a9d2b9ed565c151f61c09f29991e5faa14033da4c8", size = 11089322, upload-time = "2026-04-21T17:06:44.29Z" }, - { url = "https://files.pythonhosted.org/packages/78/c2/ce7ee2ba36aeb954ba50f18fa25d9c1188578654b97d02a66a15b6f09531/mypy-1.20.2-cp314-cp314-win_arm64.whl", hash = "sha256:c3bae4f855d965b5453784300c12ffc63a548304ac7f99e55d4dc7c898673aa3", size = 10017775, upload-time = "2026-04-21T17:07:20.732Z" }, - { url = "https://files.pythonhosted.org/packages/4e/a1/9d93a7d0b5859af0ead82b4888b46df6c8797e1bc5e1e262a08518c6d48e/mypy-1.20.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:2de3dcea53babc1c3237a19002bc3d228ce1833278f093b8d619e06e7cc79609", size = 15549002, upload-time = "2026-04-21T17:08:23.107Z" }, - { url = "https://files.pythonhosted.org/packages/00/d2/09a6a10ee1bf0008f6c144d9676f2ca6a12512151b4e0ad0ff6c4fac5337/mypy-1.20.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:52b176444e2e5054dfcbcb8c75b0b719865c96247b37407184bbfca5c353f2c2", size = 14401942, upload-time = "2026-04-21T17:07:31.837Z" }, - { url = "https://files.pythonhosted.org/packages/57/da/9594b75c3c019e805250bed3583bdf4443ff9e6ef08f97e39ae308cb06f2/mypy-1.20.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:688c3312e5dadb573a2c69c82af3a298d43ecf9e6d264e0f95df960b5f6ac19c", size = 15041649, upload-time = "2026-04-21T17:09:34.653Z" }, - { url = "https://files.pythonhosted.org/packages/97/77/f75a65c278e6e8eba2071f7f5a90481891053ecc39878cc444634d892abe/mypy-1.20.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:29752dbbf8cc53f89f6ac096d363314333045c257c9c75cbd189ca2de0455744", size = 15864588, upload-time = "2026-04-21T17:11:44.936Z" }, - { url = "https://files.pythonhosted.org/packages/d7/46/1a4e1c66e96c1a3246ddf5403d122ac9b0a8d2b7e65730b9d6533ba7a6d3/mypy-1.20.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:803203d2b6ea644982c644895c2f78b28d0e208bba7b27d9b921e0ec5eb207c6", size = 16093956, upload-time = "2026-04-21T17:10:17.683Z" }, - { url = "https://files.pythonhosted.org/packages/5a/2c/78a8851264dec38cd736ca5b8bc9380674df0dd0be7792f538916157716c/mypy-1.20.2-cp314-cp314t-win_amd64.whl", hash = "sha256:9bcb8aa397ff0093c824182fd76a935a9ba7ad097fcbef80ae89bf6c1731d8ec", size = 12568661, upload-time = "2026-04-21T17:11:54.473Z" }, - { url = "https://files.pythonhosted.org/packages/83/01/cd7318aa03493322ce275a0e14f4f52b8896335e4e79d4fb8153a7ad2b77/mypy-1.20.2-cp314-cp314t-win_arm64.whl", hash = "sha256:e061b58443f1736f8a37c48978d7ab581636d6ab03e3d4f99e3fa90463bb9382", size = 10389240, upload-time = "2026-04-21T17:09:42.719Z" }, - { url = "https://files.pythonhosted.org/packages/28/9a/f23c163e25b11074188251b0b5a0342625fc1cdb6af604757174fa9acc9b/mypy-1.20.2-py3-none-any.whl", hash = "sha256:a94c5a76ab46c5e6257c7972b6c8cff0574201ca7dc05647e33e795d78680563", size = 2637314, upload-time = "2026-04-21T17:05:54.5Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/82/6a/878cc1097d4035f82bd516658d0c528d2a9955bc7b363afcbd0b07fea11b/mypy-2.3.1.tar.gz", hash = "sha256:47c1b1207258513a9d93495f69c8be9de73916186f0e52703e8c461b7a623419", size = 3992554, upload-time = "2026-08-15T03:03:38.549Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/da/d6effc4f808a842d91edc22535dc9e799d2ff6e91449168b7f47a0771f54/mypy-2.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a32bbbb940af990d3be0b8af321c7b6815bb1b3b48142fe7459b9cc5f58959ff", size = 14047547, upload-time = "2026-08-15T03:02:57.707Z" }, + { url = "https://files.pythonhosted.org/packages/e4/e6/478229701dab76f26485fc8ff5d6f241f393da22447400bbc56f6946aebe/mypy-2.3.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff715e45b2231a8e85de1d163d1b42791e4d7aab8f5145f85fee1b710b735aff", size = 14216515, upload-time = "2026-08-15T03:01:26.496Z" }, + { url = "https://files.pythonhosted.org/packages/8d/fe/7c42327a3b21e84681f691982cbfe43f334a3685f3b683b72c376476c4fa/mypy-2.3.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:858fc57d3d91fa728e33e7ad71def60fc6272694607b306cd3292db53ae39080", size = 15307789, upload-time = "2026-08-15T03:03:31.62Z" }, + { url = "https://files.pythonhosted.org/packages/59/f4/7e597edbe01b5a56fa958ce541302dcaabfed979966f1dffedbea0ea0fc2/mypy-2.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:851833db876e7b650f93719c74b7879a08e338979c96054fdfc3bfd90a486355", size = 15548831, upload-time = "2026-08-15T03:03:15.55Z" }, + { url = "https://files.pythonhosted.org/packages/a3/52/cb31e084bc0314a1e384bdd677a4b80e55af04ccac077545e2238b9d320a/mypy-2.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:4c5095a327483591c94e0c8d3ef9e50d4ab1369b541eae007c1f23bc2a41f6bb", size = 11226359, upload-time = "2026-08-15T03:03:29.002Z" }, + { url = "https://files.pythonhosted.org/packages/7a/47/88fcf6217b43fa2da81a8c2611370af18141536a4f0294bbf98b457d456d/mypy-2.3.1-cp312-cp312-win_arm64.whl", hash = "sha256:bbfe022634a2a195406bd469e888d2eaf193b02ba7e607391cd7640374aaae3b", size = 10214707, upload-time = "2026-08-15T03:02:48.807Z" }, + { url = "https://files.pythonhosted.org/packages/de/cf/862010ee800ca9c2bd0c4c0dacf0f092e5411824a09b8f97ad4be8fe250e/mypy-2.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:114dff494000f18bd10d5d95d84b8567b26da60279ecbe838131841df20e635d", size = 13964542, upload-time = "2026-08-15T03:02:21.43Z" }, + { url = "https://files.pythonhosted.org/packages/75/5a/3f3a2107b41e3e92e617e25daaee121413b91e9784bea733131ed4fecc5d/mypy-2.3.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c8637731bb5eee3671eb2c3200827aa3564ed8a9309ecee4d1afe77e6d031bdb", size = 14168922, upload-time = "2026-08-15T03:03:00.351Z" }, + { url = "https://files.pythonhosted.org/packages/8b/41/04dc4fe7e63d7820fa4eff272e95157d30cbea921388f3ab3fe77794cd0b/mypy-2.3.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c80fbc405ed8020f5ff3802dc18cf060197bcdd3fbdd6a26ef2fd34dfdd5226", size = 15244791, upload-time = "2026-08-15T03:02:31.089Z" }, + { url = "https://files.pythonhosted.org/packages/96/fc/c3053b26b9054949285aa868cb6af8c10e7591541cacd79c5dcc06a1fcf9/mypy-2.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:84081f538ce27375045c02e3d7f81bd11d853400621ae245d87ce7b6c420ec74", size = 15501627, upload-time = "2026-08-15T03:03:34.128Z" }, + { url = "https://files.pythonhosted.org/packages/70/4e/d77daab008bbc4e5001374d7928f4a260d28f0e6747af444fc4763f7a310/mypy-2.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:e9144ac16fde007096f9563eb2041b4433c2d705c4218edeb79e7e9d01035ee6", size = 11243961, upload-time = "2026-08-15T03:02:11.952Z" }, + { url = "https://files.pythonhosted.org/packages/f0/f8/7eb68c136e4abd30569fe31ef2bfcb7eceae9952cab80017c04cd09f5d0c/mypy-2.3.1-cp313-cp313-win_arm64.whl", hash = "sha256:77ad9529e67dca28e511f5cd5671436584ce91f6d3bac159a353158187b986ac", size = 10213219, upload-time = "2026-08-15T03:02:26.361Z" }, + { url = "https://files.pythonhosted.org/packages/be/c4/42a49d44aeff804edf1b19acce0b49e8bd1a9c57dee9605dd8d980aa43d7/mypy-2.3.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:192abaedf75da1bc0b1cef104927e70ec49c1ef0031cc4825c7ee10a438ed24d", size = 13986778, upload-time = "2026-08-15T03:01:33.69Z" }, + { url = "https://files.pythonhosted.org/packages/45/13/9331fd2dfed7194d66c5304072894a8be3e51e9deda6863c1eceaa35a43d/mypy-2.3.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf678dffd16efcda2c15cbd30e9ecc0081388e29ea23687a88e686ed92638dc3", size = 14188467, upload-time = "2026-08-15T03:02:40.554Z" }, + { url = "https://files.pythonhosted.org/packages/78/f7/f4a34edab45667c5465855dc585a20e87978ffa8aee711445b7239d120c6/mypy-2.3.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e036f06b41630f4c8a1d48f9ac6aa26acc65f8be089973f5519da643318f03f", size = 15225538, upload-time = "2026-08-15T03:03:09.761Z" }, + { url = "https://files.pythonhosted.org/packages/40/05/534b3590757bd05794f73e07f6666c2a77b8597ffed795c94ce570096aa0/mypy-2.3.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:71af9c8a894e862b58e92abb08e53b05a384a1e5e5d6dc7cda59126211a53d82", size = 15480805, upload-time = "2026-08-15T03:01:41.134Z" }, + { url = "https://files.pythonhosted.org/packages/55/da/bdfba852e2562f599624af5bb7d29e36b0b4f526f2b8bac85efe0dd1803d/mypy-2.3.1-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:3c80cd23d85368bdd9f37d5231dfd97d35bcbf5bf41af96ef3a9b078ad1957f9", size = 7761712, upload-time = "2026-08-15T03:02:36.008Z" }, + { url = "https://files.pythonhosted.org/packages/98/31/60fc64a74cdba4f2a5d642d32317993e479163e1ac7d91b695e5d15e2264/mypy-2.3.1-cp314-cp314-win_amd64.whl", hash = "sha256:4956f34d145e145562a0a0bf367f642bbc85c04ec2baf47ae015947c3169a85d", size = 11423968, upload-time = "2026-08-15T03:02:06.931Z" }, + { url = "https://files.pythonhosted.org/packages/a9/23/eb5950b24cd26ba3b78f87707a275568d633c77dae8e61c9661be6055ca6/mypy-2.3.1-cp314-cp314-win_arm64.whl", hash = "sha256:cfb12e360242d23d91f5e978d94f58ea66acf5804c4fb6f2f794a20d4cb1b595", size = 10399323, upload-time = "2026-08-15T03:02:33.671Z" }, + { url = "https://files.pythonhosted.org/packages/82/c7/f80f4e46c0b9a00eb5f78a79d49dda8bdf56a5230f7257fb33e76be04da7/mypy-2.3.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e5f1c50bb05b64e2026b52867e8d21106f01313c744a2c4ecc34c90d12e8d6e2", size = 15121308, upload-time = "2026-08-15T03:01:46.053Z" }, + { url = "https://files.pythonhosted.org/packages/5d/74/9b04f17c7074cc5188f02fb63a2ca1d43fedf479e84fe3091c39061a1d7f/mypy-2.3.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:667196b352f4cf304ded4c10f90cfc179263a1acfb3cdcfa984bdfd340d498bc", size = 15536590, upload-time = "2026-08-15T03:01:35.941Z" }, + { url = "https://files.pythonhosted.org/packages/26/04/c837ef6208e567774e2ed1f863f8ba6ec4817b1b6dd426315e5d559b6ec9/mypy-2.3.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b9c53e395c12cad2c6d4b67d5da7c6057638a132d85c08b73646b18f802a0045", size = 16791074, upload-time = "2026-08-15T03:01:31.073Z" }, + { url = "https://files.pythonhosted.org/packages/37/68/48730230afa45192d5bd429a6a2ff24a6f8dedda90fdf2b221792b54518f/mypy-2.3.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:18162b128c3f9c703cd35f5537446900b0d21a2549aa7a95d21380d2ef643fb0", size = 17069183, upload-time = "2026-08-15T03:02:28.566Z" }, + { url = "https://files.pythonhosted.org/packages/1c/ea/ca23fc9c20eeda09a15c9cbcf50015d0e73f409f6ead059e42aa69a608ff/mypy-2.3.1-cp314-cp314t-win_amd64.whl", hash = "sha256:30c0477d4aab7b7f39c8397dc877f2c96b9fe5588ec379f372c56eb63d599f63", size = 12154679, upload-time = "2026-08-15T03:02:04.809Z" }, + { url = "https://files.pythonhosted.org/packages/3b/67/8d982126034990869466f73b8db80dcb2234a7ac39b4dad093e047a79835/mypy-2.3.1-cp314-cp314t-win_arm64.whl", hash = "sha256:6941ab3619377bc3f32ca02876b07d27f216f5201604b664d3937ea0fdd23bb4", size = 10969159, upload-time = "2026-08-15T03:02:38.152Z" }, + { url = "https://files.pythonhosted.org/packages/ee/f7/41e7f2d8117fbc7a7587286162ffe2f688984b69c46ed63cf5f2e4fc3bae/mypy-2.3.1-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:6f041a6de52c9217ca125e78ba0a335cb7fd98a1c0580978e49ab2b126f70b57", size = 13990694, upload-time = "2026-08-15T03:03:21.919Z" }, + { url = "https://files.pythonhosted.org/packages/06/85/8f665811a0c8f3bf6fa1d9acd665ec2d97a2bcc453ae68dcd92340941cd6/mypy-2.3.1-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5159ae60f5dbc3a498af5ba8365505808ac8031bc63f9e00304ad545d40bdd9b", size = 14203518, upload-time = "2026-08-15T03:01:48.455Z" }, + { url = "https://files.pythonhosted.org/packages/2d/82/91b866c8546b120bff83b73a439d90d2d63ef3aff113599e6b8e4d566848/mypy-2.3.1-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47a8a7a0a7f6f6e63995c0ac36fa0c07b127413fdc81f0439b7f3dccafd33561", size = 15220224, upload-time = "2026-08-15T03:01:23.577Z" }, + { url = "https://files.pythonhosted.org/packages/c8/78/c226c99208ee40de7c768369fa533f933afa003dfdc606ff021450724e91/mypy-2.3.1-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:2329c0501293d4e1f33bc15d04d6304d65a1cdda967ee93a05c1e681a3923133", size = 15501512, upload-time = "2026-08-15T03:02:09.453Z" }, + { url = "https://files.pythonhosted.org/packages/a9/e7/7cfb3f106c393979f4cc37ad6c0586044d50401e3c35b0c003e4f3ba6bc9/mypy-2.3.1-cp315-cp315-pyemscripten_2026_5_wasm32.whl", hash = "sha256:bb26deed807bdb0457cf3e3f1cd7c4a1cf9d66864eaf1b4a61e06805d4c6b1f9", size = 7761913, upload-time = "2026-08-15T03:01:55.65Z" }, + { url = "https://files.pythonhosted.org/packages/99/3c/52affefa273b97939a1f474ae4a349c8718635c15b941112dfab4291b0c1/mypy-2.3.1-cp315-cp315-win_amd64.whl", hash = "sha256:375d7013876a8233b2d05be185bfa09f689696cd999ce8b1cfe6acac5c80e8a3", size = 11422533, upload-time = "2026-08-15T03:03:24.101Z" }, + { url = "https://files.pythonhosted.org/packages/2a/b7/75643e70c72a5b346d8a9b1543c967ea8824df2ee3fb7ccba652c272b7bb/mypy-2.3.1-cp315-cp315-win_arm64.whl", hash = "sha256:586b3612214cceabb3c0f588c97e7d1e535393f06a60e912e994f6b3ace97523", size = 10397931, upload-time = "2026-08-15T03:02:55.265Z" }, + { url = "https://files.pythonhosted.org/packages/10/ce/53be21f2d4adfcd26f63f1184a13ed797015ab463853f117e2e11e4d726f/mypy-2.3.1-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:ef0c6335cda9d807f8193d8ff6204a72bc909fa9882aacbca14f43cdb7188306", size = 15118669, upload-time = "2026-08-15T03:02:51.479Z" }, + { url = "https://files.pythonhosted.org/packages/62/43/20de757cd42989d291a17fad607742c4c74e875ce5cea00e5a5225020ac1/mypy-2.3.1-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e598c8c66401d26b150872154a286e6d484cf2789c3bb28a7556806298423021", size = 15545627, upload-time = "2026-08-15T03:03:05.132Z" }, + { url = "https://files.pythonhosted.org/packages/7e/fc/092bdf77ad280eaf501422f0f3b966012b528076cc13e41a774861c907d1/mypy-2.3.1-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eda22fd4efa9dcd39331d1dede9b5b8b8a7fd69af07592e778433da98610d29e", size = 16764157, upload-time = "2026-08-15T03:02:23.958Z" }, + { url = "https://files.pythonhosted.org/packages/94/5c/c94c4d62d909b07f552d0d9356d7acc943825558e602a64822ffa2231536/mypy-2.3.1-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:2a0ba2e57847849fb0d1fcdabb32786d223095ed8bc121dfe322bcdb3d9c46bc", size = 17073258, upload-time = "2026-08-15T03:02:14.573Z" }, + { url = "https://files.pythonhosted.org/packages/c0/f7/511a88b89e478053c02d22039bb8f3ce4183efe8fd7a4f0a5910a8bb0a32/mypy-2.3.1-cp315-cp315t-win_amd64.whl", hash = "sha256:3f7e865dd51f235f60a2dbcd8728a1c095f5ca28f095d48a725b84cd935735c4", size = 12135505, upload-time = "2026-08-15T03:02:16.714Z" }, + { url = "https://files.pythonhosted.org/packages/71/bf/02573b56964ecb0f7c644f915f53c325ae15c3faec521c5adf11599a32df/mypy-2.3.1-cp315-cp315t-win_arm64.whl", hash = "sha256:8ad80807dc3ab8ea978b1b2b6e4a657194ace1d4ef03e0e731aff1abd517da29", size = 10962647, upload-time = "2026-08-15T03:01:43.712Z" }, + { url = "https://files.pythonhosted.org/packages/8e/41/9675c7a1e78edecfba0b79e587a52594c56e189368261dc7b3a7fffb9527/mypy-2.3.1-py3-none-any.whl", hash = "sha256:6ed5c7e3419083268e5c9258bd1c1ef91af44a9e89374dbcaf37b775716e72eb", size = 2754338, upload-time = "2026-08-15T03:02:53.4Z" }, ] [[package]] @@ -4664,19 +4784,19 @@ wheels = [ [[package]] name = "tornado" -version = "6.5.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/64/24/95ec527ad67b76d59299e5465b3935d05e4294b7e0290a3924b7487df30b/tornado-6.5.7.tar.gz", hash = "sha256:66c513a76cda70d53907bc27cf1447557699c2e95aa48ba27a442ff61c3ddfc2", size = 519252, upload-time = "2026-06-08T17:34:51.232Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/02/dc/c7043cab6fed8ae159fc1923ce829ada35c4dbd797d408a43858ffaf9639/tornado-6.5.7-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:148b2eb15c2c765a50796172c1e499649b35f30d2e3c3d3e15913cfa56bfb163", size = 448543, upload-time = "2026-06-08T17:34:38.052Z" }, - { url = "https://files.pythonhosted.org/packages/92/4f/090b1431e5a43df696feceffc268c5383cc079ecb5f08ce58f917109aafe/tornado-6.5.7-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9da38de27f1da3b78a966f0dae12b5a1ea9afe72ca805d84ff06508272ddf100", size = 446707, upload-time = "2026-06-08T17:34:39.594Z" }, - { url = "https://files.pythonhosted.org/packages/37/d8/ef374952fd5da67d4463122c2b8e5a96536ec10b4b339254c6dcde81d01c/tornado-6.5.7-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8d759e71906ee783f8867b93bf26a265743da4c1e2f4a018464c1ba019862972", size = 449774, upload-time = "2026-06-08T17:34:41.204Z" }, - { url = "https://files.pythonhosted.org/packages/35/37/d434c73f4c6e014b745b9b37085f34f40c022f007efff3d7fe65991899f3/tornado-6.5.7-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a46347a18f23fb92b396beebe0fb78f61dda0cc302445202c16203d8a18848b", size = 450745, upload-time = "2026-06-08T17:34:42.531Z" }, - { url = "https://files.pythonhosted.org/packages/b6/2b/56b9aff361d7f1ab728a805ec7d7ea835f8807afa9f5cc690ea0e630efb9/tornado-6.5.7-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7778b30bef919231265e91c69963ce0f49a1e9c07ac900bbe75b19ce2575ba92", size = 450578, upload-time = "2026-06-08T17:34:43.787Z" }, - { url = "https://files.pythonhosted.org/packages/02/30/a7444fb23aa76860a14198fab96ac79f1866b0a6e19e26c4381b0938e50f/tornado-6.5.7-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e726f0c75da7726eec023aa62751ff8878bd2737e34fbdd33b1ae5897d2200f5", size = 449985, upload-time = "2026-06-08T17:34:45.326Z" }, - { url = "https://files.pythonhosted.org/packages/5c/42/5f0e56c01e8d9d36f4e23f367b85ae6cae0c1ecddd5e6977d8388ad27488/tornado-6.5.7-cp39-abi3-win32.whl", hash = "sha256:f8de3bf12d3efdd0cbe7c8887868198f8a91415e3f29fcf258d9b8eb7b1d9ae4", size = 451047, upload-time = "2026-06-08T17:34:46.784Z" }, - { url = "https://files.pythonhosted.org/packages/c9/a4/b393076ffb21b469eec5b328a0534cf03a3b90bfc6b1f09507cdd075d938/tornado-6.5.7-cp39-abi3-win_amd64.whl", hash = "sha256:de942f843533a039ef9fa3d9c88c7cd8a7c94553fb5ad0154270989b3d99a2c4", size = 451485, upload-time = "2026-06-08T17:34:48.248Z" }, - { url = "https://files.pythonhosted.org/packages/71/2e/7b1c769803121b809112cf9a00681c472eae1d80e32d7ec0e0bd61d0d0e1/tornado-6.5.7-cp39-abi3-win_arm64.whl", hash = "sha256:ff934fce95643af5f11efdae618eaa73d469dc588641e5c8d19295a0c65c4796", size = 450506, upload-time = "2026-06-08T17:34:49.702Z" }, +version = "6.5.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/10/d3/343e5bb989d6515b1646cf3d40135d73f3d5e45339bded401b56cdac24dd/tornado-6.5.8.tar.gz", hash = "sha256:9452e1b208a8bd771e2cb1f2ff564985b9b214bdebbe622793e1799e0a6bd23f", size = 520493, upload-time = "2026-08-07T02:12:42.971Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/d5/007086fd8df5489338e204f65adce33fd4f21a4999dbb2b9cff2f897b5f4/tornado-6.5.8-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:cc6aa787d7cfab7c3d35189dc7a56fbd2399a569624c730c6b55b3d6531d0403", size = 449487, upload-time = "2026-08-07T02:12:28.682Z" }, + { url = "https://files.pythonhosted.org/packages/70/c8/5a24a99495903f594f6a199dd7beead1cbc0a13e2cb9102727bcaaf2a997/tornado-6.5.8-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9715b5eb79735b2bcd454ce216a9275b7c0470e64ea1bf5742f78b2f72b26eeb", size = 447649, upload-time = "2026-08-07T02:12:30.306Z" }, + { url = "https://files.pythonhosted.org/packages/6e/de/f2e733f386b85962d1b1dc82cd63d169b5b4580062b35397eac9244a41fe/tornado-6.5.8-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:547d63f450d570c14fe0e8db2cfb14c9bbd1c2503b4a6612586267955aa47b58", size = 450707, upload-time = "2026-08-07T02:12:31.95Z" }, + { url = "https://files.pythonhosted.org/packages/0b/94/20efeee9a01c141e9ac47c397f81679dfda24b32768fc4fff24e76d36c2c/tornado-6.5.8-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7e2360a0ffbe145eca8af0b19cb7203d79b1a98dd4cccdd6b368f6f49c2e3808", size = 451677, upload-time = "2026-08-07T02:12:33.512Z" }, + { url = "https://files.pythonhosted.org/packages/42/ec/a96ccb8ccf0de2b7bc2c5fa1608a4803735018242e90c4882365a9fd418f/tornado-6.5.8-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:5d242290bdf7ab3151bc1065fdd75c0dcc21cbc7b49f22a4c56329c2d6566d22", size = 451510, upload-time = "2026-08-07T02:12:35.346Z" }, + { url = "https://files.pythonhosted.org/packages/29/b5/93185859245ad3f00e62175f29607346788b696369347f0146e0421286bb/tornado-6.5.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7b94ff0e128fe0542f3bd331fb44d06260fc4ac16881545159f34ef08aad4195", size = 450917, upload-time = "2026-08-07T02:12:36.963Z" }, + { url = "https://files.pythonhosted.org/packages/97/cf/fe33cf062834487d34d1559746a4a12521033c22645b6d74d4bca702e018/tornado-6.5.8-cp39-abi3-win32.whl", hash = "sha256:67832909c4779c64942380cb5f044a5c6163d00831472d80e25e115de9917836", size = 451952, upload-time = "2026-08-07T02:12:38.512Z" }, + { url = "https://files.pythonhosted.org/packages/cb/e1/468ad54333e92ccb62627e62cb88e5fc14a2171daa67ed47b1b8542d5b86/tornado-6.5.8-cp39-abi3-win_amd64.whl", hash = "sha256:11881db6b7c168494be2c2d12e65931451bdf7ee718535418ae1d8855dd5a0ee", size = 452391, upload-time = "2026-08-07T02:12:39.971Z" }, + { url = "https://files.pythonhosted.org/packages/ad/3e/cd5e4f06e34cde33b8ef66cf36aa2b5ad46354cc1af7d2136bbe365fee1d/tornado-6.5.8-cp39-abi3-win_arm64.whl", hash = "sha256:68a7468c7e289f8514d7d664101753903217eff1bb6822c6b5994a0b5f5bcb26", size = 451411, upload-time = "2026-08-07T02:12:41.469Z" }, ] [[package]]