acmadDL 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- acmaddl-0.2.0/.github/workflows/add-to-kanban.yml +14 -0
- acmaddl-0.2.0/.github/workflows/publish-testpypi.yml +18 -0
- acmaddl-0.2.0/.github/workflows/publish.yml +47 -0
- acmaddl-0.2.0/.github/workflows/test.yml +22 -0
- acmaddl-0.2.0/.gitignore +51 -0
- acmaddl-0.2.0/AGENTS.md +34 -0
- acmaddl-0.2.0/LICENSE +21 -0
- acmaddl-0.2.0/PKG-INFO +338 -0
- acmaddl-0.2.0/README.md +291 -0
- acmaddl-0.2.0/docs/specs/2026-07-09-issuance-keyed-forecasts-design.md +91 -0
- acmaddl-0.2.0/docs/specs/2026-07-09-opendap-truncation-and-zonal-design.md +77 -0
- acmaddl-0.2.0/packaging/accord-rosetta/README.md +19 -0
- acmaddl-0.2.0/packaging/accord-rosetta/pyproject.toml +41 -0
- acmaddl-0.2.0/pyproject.toml +98 -0
- acmaddl-0.2.0/scripts/check_push_creds.sh +67 -0
- acmaddl-0.2.0/scripts/demo.ipynb +591 -0
- acmaddl-0.2.0/scripts/demo_shapefile_region.py +117 -0
- acmaddl-0.2.0/scripts/download_nmme_hindcasts.py +217 -0
- acmaddl-0.2.0/scripts/fetch_country_shapefiles.py +68 -0
- acmaddl-0.2.0/scripts/validate_against_iri.py +830 -0
- acmaddl-0.2.0/skills/acmaddl/README.md +54 -0
- acmaddl-0.2.0/skills/acmaddl/SKILL.md +225 -0
- acmaddl-0.2.0/skills/acmaddl/examples/basic_fetch.py +67 -0
- acmaddl-0.2.0/skills/acmaddl/examples/chirps_gefs_issuance.py +45 -0
- acmaddl-0.2.0/skills/acmaddl/examples/multi_model_assemble.py +40 -0
- acmaddl-0.2.0/skills/acmaddl/examples/quick_look.py +47 -0
- acmaddl-0.2.0/skills/acmaddl/examples/s2s_fetch.py +47 -0
- acmaddl-0.2.0/skills/acmaddl/examples/shapefile_region.py +43 -0
- acmaddl-0.2.0/skills/acmaddl/examples/zonal_districts.py +51 -0
- acmaddl-0.2.0/skills/acmaddl/references/api.md +198 -0
- acmaddl-0.2.0/skills/acmaddl/references/data-conventions.md +84 -0
- acmaddl-0.2.0/skills/acmaddl/references/plotting.md +102 -0
- acmaddl-0.2.0/skills/acmaddl/references/products.md +130 -0
- acmaddl-0.2.0/skills/acmaddl/references/troubleshooting.md +82 -0
- acmaddl-0.2.0/src/acmaddl/__init__.py +61 -0
- acmaddl-0.2.0/src/acmaddl/_paths.py +51 -0
- acmaddl-0.2.0/src/acmaddl/adapters/__init__.py +34 -0
- acmaddl-0.2.0/src/acmaddl/adapters/_issuance.py +124 -0
- acmaddl-0.2.0/src/acmaddl/adapters/_robust.py +152 -0
- acmaddl-0.2.0/src/acmaddl/adapters/base.py +60 -0
- acmaddl-0.2.0/src/acmaddl/adapters/ccsr.py +239 -0
- acmaddl-0.2.0/src/acmaddl/adapters/cds.py +270 -0
- acmaddl-0.2.0/src/acmaddl/adapters/cpc_binary.py +102 -0
- acmaddl-0.2.0/src/acmaddl/adapters/http.py +465 -0
- acmaddl-0.2.0/src/acmaddl/adapters/icechunk.py +172 -0
- acmaddl-0.2.0/src/acmaddl/adapters/iridl.py +141 -0
- acmaddl-0.2.0/src/acmaddl/adapters/mars.py +124 -0
- acmaddl-0.2.0/src/acmaddl/adapters/ncei.py +209 -0
- acmaddl-0.2.0/src/acmaddl/adapters/opendap.py +272 -0
- acmaddl-0.2.0/src/acmaddl/adapters/s3.py +159 -0
- acmaddl-0.2.0/src/acmaddl/adapters/sheerwater.py +175 -0
- acmaddl-0.2.0/src/acmaddl/assemble.py +93 -0
- acmaddl-0.2.0/src/acmaddl/catalog.py +90 -0
- acmaddl-0.2.0/src/acmaddl/catalog.yaml +1613 -0
- acmaddl-0.2.0/src/acmaddl/cli.py +36 -0
- acmaddl-0.2.0/src/acmaddl/cpc_nmme.py +123 -0
- acmaddl-0.2.0/src/acmaddl/errors.py +33 -0
- acmaddl-0.2.0/src/acmaddl/fetch.py +573 -0
- acmaddl-0.2.0/src/acmaddl/health.py +88 -0
- acmaddl-0.2.0/src/acmaddl/normalize.py +438 -0
- acmaddl-0.2.0/src/acmaddl/nuthatch.toml +22 -0
- acmaddl-0.2.0/src/acmaddl/region.py +111 -0
- acmaddl-0.2.0/src/acmaddl/storage.py +79 -0
- acmaddl-0.2.0/src/acmaddl/validate.py +423 -0
- acmaddl-0.2.0/src/acmaddl/zonal.py +265 -0
- acmaddl-0.2.0/src/rosetta/__init__.py +65 -0
- acmaddl-0.2.0/tests/__init__.py +0 -0
- acmaddl-0.2.0/tests/conftest.py +127 -0
- acmaddl-0.2.0/tests/test_acmaddl.py +1284 -0
- acmaddl-0.2.0/tests/test_adapter_registry.py +25 -0
- acmaddl-0.2.0/tests/test_assemble.py +63 -0
- acmaddl-0.2.0/tests/test_base_adapter.py +38 -0
- acmaddl-0.2.0/tests/test_cache.py +486 -0
- acmaddl-0.2.0/tests/test_catalog_alias.py +56 -0
- acmaddl-0.2.0/tests/test_catalog_integrity.py +232 -0
- acmaddl-0.2.0/tests/test_ccsr_adapter.py +333 -0
- acmaddl-0.2.0/tests/test_cfsv2_members.py +164 -0
- acmaddl-0.2.0/tests/test_chirps_catalog.py +158 -0
- acmaddl-0.2.0/tests/test_cmap_tamsat_catalog.py +31 -0
- acmaddl-0.2.0/tests/test_cmcc_catalog.py +130 -0
- acmaddl-0.2.0/tests/test_cpc_nmme_cache.py +47 -0
- acmaddl-0.2.0/tests/test_degenerate_response.py +92 -0
- acmaddl-0.2.0/tests/test_era5_land_catalog.py +120 -0
- acmaddl-0.2.0/tests/test_ersst_catalog.py +225 -0
- acmaddl-0.2.0/tests/test_fetch_enrichment.py +109 -0
- acmaddl-0.2.0/tests/test_integration.py +1017 -0
- acmaddl-0.2.0/tests/test_issuance.py +523 -0
- acmaddl-0.2.0/tests/test_lon_convention.py +101 -0
- acmaddl-0.2.0/tests/test_lon_convention_interp.py +26 -0
- acmaddl-0.2.0/tests/test_mars_adapter.py +118 -0
- acmaddl-0.2.0/tests/test_normalize_name_skew.py +39 -0
- acmaddl-0.2.0/tests/test_obs_predictor.py +64 -0
- acmaddl-0.2.0/tests/test_opendap_adapter.py +250 -0
- acmaddl-0.2.0/tests/test_opendap_retry.py +163 -0
- acmaddl-0.2.0/tests/test_region.py +406 -0
- acmaddl-0.2.0/tests/test_rename_compat.py +129 -0
- acmaddl-0.2.0/tests/test_s2s_adapter.py +331 -0
- acmaddl-0.2.0/tests/test_seasonal_precip_units.py +66 -0
- acmaddl-0.2.0/tests/test_seasons.py +44 -0
- acmaddl-0.2.0/tests/test_sheerwater.py +177 -0
- acmaddl-0.2.0/tests/test_sheerwater_catalog.py +85 -0
- acmaddl-0.2.0/tests/test_sheerwater_integration.py +54 -0
- acmaddl-0.2.0/tests/test_spec.md +252 -0
- acmaddl-0.2.0/tests/test_validate.py +393 -0
- acmaddl-0.2.0/tests/test_variable_not_supported.py +275 -0
- acmaddl-0.2.0/tests/test_zonal.py +356 -0
- acmaddl-0.2.0/uv.lock +5167 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
name: Add issues to Kanban
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
issues:
|
|
5
|
+
types: [opened, reopened]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
add-to-kanban:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/add-to-project@v1.0.2
|
|
12
|
+
with:
|
|
13
|
+
project-url: https://github.com/orgs/accord-research/projects/2
|
|
14
|
+
github-token: ${{ secrets.KANBAN_TOKEN }}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
name: publish-testpypi
|
|
2
|
+
on:
|
|
3
|
+
workflow_dispatch:
|
|
4
|
+
|
|
5
|
+
permissions:
|
|
6
|
+
id-token: write
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build-publish-test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
environment: testpypi
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
- uses: astral-sh/setup-uv@v6
|
|
15
|
+
- run: uv build
|
|
16
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
17
|
+
with:
|
|
18
|
+
repository-url: https://test.pypi.org/legacy/
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
name: publish
|
|
2
|
+
|
|
3
|
+
# PyPI releases are cut MANUALLY, never on a push to main.
|
|
4
|
+
#
|
|
5
|
+
# To release:
|
|
6
|
+
# 1. Bump `version` in pyproject.toml (in a commit to main).
|
|
7
|
+
# 2. Actions tab -> "publish" -> "Run workflow".
|
|
8
|
+
#
|
|
9
|
+
# The job publishes only if that version isn't already on PyPI, so re-running
|
|
10
|
+
# without a version bump is a safe no-op (it fails fast with a clear message).
|
|
11
|
+
# pyproject.toml's `version` is the single source of truth. Publishing uses
|
|
12
|
+
# PyPI Trusted Publishing (no tokens).
|
|
13
|
+
|
|
14
|
+
on:
|
|
15
|
+
workflow_dispatch:
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
test:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
- uses: astral-sh/setup-uv@v6
|
|
23
|
+
with:
|
|
24
|
+
python-version: "3.12"
|
|
25
|
+
- run: uv sync --extra dev
|
|
26
|
+
- run: uv run pytest -m "not network and not integration and not cds" -q
|
|
27
|
+
|
|
28
|
+
publish:
|
|
29
|
+
needs: test
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
environment: pypi
|
|
32
|
+
permissions:
|
|
33
|
+
id-token: write
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v4
|
|
36
|
+
- uses: astral-sh/setup-uv@v6
|
|
37
|
+
- name: Refuse to republish an existing version
|
|
38
|
+
run: |
|
|
39
|
+
VERSION=$(grep -E '^version = ' pyproject.toml | head -1 | sed -E 's/version = "(.*)"/\1/')
|
|
40
|
+
echo "pyproject.toml version: $VERSION"
|
|
41
|
+
if curl -sf "https://pypi.org/pypi/acmadDL/$VERSION/json" > /dev/null; then
|
|
42
|
+
echo "::error::acmadDL $VERSION is already on PyPI — bump 'version' in pyproject.toml first."
|
|
43
|
+
exit 1
|
|
44
|
+
fi
|
|
45
|
+
echo "$VERSION is new on PyPI; proceeding to publish."
|
|
46
|
+
- run: uv build
|
|
47
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: Unit tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
|
|
13
|
+
- name: Install uv
|
|
14
|
+
uses: astral-sh/setup-uv@v4
|
|
15
|
+
with:
|
|
16
|
+
python-version: "3.12"
|
|
17
|
+
|
|
18
|
+
- name: Install dependencies
|
|
19
|
+
run: uv sync --extra dev
|
|
20
|
+
|
|
21
|
+
- name: Run unit tests
|
|
22
|
+
run: uv run pytest tests/test_acmaddl.py tests/test_sheerwater.py tests/test_cache.py tests/test_validate.py -q -m "not network and not integration and not cds"
|
acmaddl-0.2.0/.gitignore
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Python bytecode and caches
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.so
|
|
5
|
+
|
|
6
|
+
# Local virtual environments
|
|
7
|
+
.venv/
|
|
8
|
+
venv/
|
|
9
|
+
|
|
10
|
+
# Test and tooling caches
|
|
11
|
+
.pytest_cache/
|
|
12
|
+
.mypy_cache/
|
|
13
|
+
.ruff_cache/
|
|
14
|
+
.coverage
|
|
15
|
+
.coverage.*
|
|
16
|
+
htmlcov/
|
|
17
|
+
|
|
18
|
+
# Notebook and editor noise
|
|
19
|
+
.ipynb_checkpoints/
|
|
20
|
+
.DS_Store
|
|
21
|
+
|
|
22
|
+
# Local data/artifacts
|
|
23
|
+
data/
|
|
24
|
+
cache/
|
|
25
|
+
tmp/
|
|
26
|
+
# generated demo PNGs + regenerated catalog HTML/text
|
|
27
|
+
output/
|
|
28
|
+
*.nc
|
|
29
|
+
*.zarr/
|
|
30
|
+
*.grib
|
|
31
|
+
*.grb
|
|
32
|
+
*.tif
|
|
33
|
+
*.tiff
|
|
34
|
+
|
|
35
|
+
# Local secrets/config (do not commit credentials)
|
|
36
|
+
.env
|
|
37
|
+
.env.*
|
|
38
|
+
*.pem
|
|
39
|
+
*.key
|
|
40
|
+
*credentials*.json
|
|
41
|
+
.cdsapirc
|
|
42
|
+
.ecmwfapirc
|
|
43
|
+
.netrc
|
|
44
|
+
.dodsrc
|
|
45
|
+
|
|
46
|
+
.claude_env
|
|
47
|
+
|
|
48
|
+
# Git worktrees
|
|
49
|
+
.worktrees/
|
|
50
|
+
|
|
51
|
+
docs/superpowers
|
acmaddl-0.2.0/AGENTS.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Agent instructions for acmaddl
|
|
2
|
+
|
|
3
|
+
Instructions for any AI coding agent (Claude Code, Codex, OpenCode, etc.) working in this repository.
|
|
4
|
+
|
|
5
|
+
## Before you start
|
|
6
|
+
|
|
7
|
+
Read [`skills/acmaddl/SKILL.md`](skills/acmaddl/SKILL.md) before writing or modifying code that uses acmaddl. It is the authoritative quick reference for the public API, product catalog, data conventions, credentials, and caching behavior, with deeper detail in `skills/acmaddl/references/`. If your harness supports Agent Skills natively, load the skill instead of re-deriving the API from source.
|
|
8
|
+
|
|
9
|
+
## Keep the docs and skill in sync — this is a hard requirement
|
|
10
|
+
|
|
11
|
+
The skill is a snapshot of the source. Any change that alters observable behavior MUST update the matching documentation **in the same PR**:
|
|
12
|
+
|
|
13
|
+
| If you change... | You must update... |
|
|
14
|
+
|---|---|
|
|
15
|
+
| `fetch()` / `assemble()` signatures, defaults, or behavior | `skills/acmaddl/SKILL.md` + `skills/acmaddl/references/api.md` |
|
|
16
|
+
| `fetch()` params `months`, `degenerate_attempts`, `init` sequence / issuance handling | `skills/acmaddl/references/api.md` (params) + `data-conventions.md` (issuance `init_time`/`lead_time`/`valid_time`) + `SKILL.md` |
|
|
17
|
+
| `zonal.py` (`acmaddl.zonal` signature, stats, weights, gotchas) | `skills/acmaddl/references/api.md` + `SKILL.md` (+ `examples/zonal_districts.py`) |
|
|
18
|
+
| `assemble.py` `obs_predictor` (obs-as-predictor signature/behavior) | `skills/acmaddl/references/api.md` + `SKILL.md` |
|
|
19
|
+
| `catalog.yaml` (add/remove/deprecate products, variables, adapters) | `skills/acmaddl/references/products.md` (+ `SKILL.md` product families if a new family) |
|
|
20
|
+
| Issuance-keyed catalog entries (CHIRPS-GEFS) or OPeNDAP obs entries (ERSST/CMAP, `max_request_years`) | `skills/acmaddl/references/products.md` + `data-conventions.md` (issuance layout) + `troubleshooting.md` (truncation guard) + `examples/chirps_gefs_issuance.py` |
|
|
21
|
+
| `normalize.py` (renames, unit conversions, pipeline order, `select_lon`/`sanitize_for_netcdf`) | `skills/acmaddl/references/data-conventions.md` (+ `plotting.md` if dims/units/orientation guarantees change) |
|
|
22
|
+
| Degenerate-response guard (`_robust.reject_if_degenerate`, `DegenerateResponseError`, opt-in vs always-on) | `skills/acmaddl/references/troubleshooting.md` + `api.md` (`degenerate_attempts`) |
|
|
23
|
+
| Caching (`_CACHE_VERSION`, cache keys, env vars, nuthatch config) | `skills/acmaddl/references/troubleshooting.md` |
|
|
24
|
+
| Credentials/adapters (new source, auth flow, rate limits) | `skills/acmaddl/references/products.md` + `troubleshooting.md` |
|
|
25
|
+
| Anything user-facing | `README.md` if it covers the topic |
|
|
26
|
+
|
|
27
|
+
Also update `skills/acmaddl/examples/` if a change breaks or obsoletes an example. If you are unsure whether a change is documented, grep `skills/` and `README.md` for the function, product id, or parameter you touched — stale docs are treated as bugs.
|
|
28
|
+
|
|
29
|
+
## Repo conventions
|
|
30
|
+
|
|
31
|
+
- Package layout: `src/acmaddl/` (import name `acmaddl`, distribution `acmadDL`). Python ≥ 3.12, `uv` for dependency management.
|
|
32
|
+
- Tests: `pytest` for the unit suite; markers `integration`, `cds`, `network` gate live-network tests. New behavior needs tests.
|
|
33
|
+
- Caching lives only in `fetch._fetch_raw_cached` — never add `@cache` decorators inside adapters. Bump `_CACHE_VERSION` when adapter logic or normalization changes output.
|
|
34
|
+
- The catalog is declarative: prefer adding/adjusting `catalog.yaml` entries over special-casing code paths.
|
acmaddl-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 accord-research
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
acmaddl-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: acmadDL
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Canonical data acquisition for seasonal climate forecasting
|
|
5
|
+
Project-URL: Homepage, https://github.com/ACMAD-Niamey/acmadDL
|
|
6
|
+
Project-URL: Repository, https://github.com/ACMAD-Niamey/acmadDL
|
|
7
|
+
Author: accord-research
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: cds,chirps,climate,data-acquisition,forecasting,xarray
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
|
|
16
|
+
Requires-Python: >=3.12
|
|
17
|
+
Requires-Dist: cdsapi>=0.7.7
|
|
18
|
+
Requires-Dist: cfgrib>=0.9.15.1
|
|
19
|
+
Requires-Dist: earthaccess>=0.18
|
|
20
|
+
Requires-Dist: eccodeslib>=2.46.2.19
|
|
21
|
+
Requires-Dist: ecmwf-api-client>=1.6
|
|
22
|
+
Requires-Dist: fsspec>=2025.2
|
|
23
|
+
Requires-Dist: netcdf4
|
|
24
|
+
Requires-Dist: numpy
|
|
25
|
+
Requires-Dist: nuthatch>=0.4.9
|
|
26
|
+
Requires-Dist: pyyaml
|
|
27
|
+
Requires-Dist: rioxarray
|
|
28
|
+
Requires-Dist: s3fs>=2025.2
|
|
29
|
+
Requires-Dist: scipy
|
|
30
|
+
Requires-Dist: sheerwater>=0.2.5
|
|
31
|
+
Requires-Dist: tqdm
|
|
32
|
+
Requires-Dist: xarray
|
|
33
|
+
Provides-Extra: demo
|
|
34
|
+
Requires-Dist: cartopy; extra == 'demo'
|
|
35
|
+
Requires-Dist: matplotlib; extra == 'demo'
|
|
36
|
+
Requires-Dist: rasterio; extra == 'demo'
|
|
37
|
+
Provides-Extra: dev
|
|
38
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
39
|
+
Provides-Extra: geo
|
|
40
|
+
Requires-Dist: geopandas; extra == 'geo'
|
|
41
|
+
Requires-Dist: rasterio; extra == 'geo'
|
|
42
|
+
Provides-Extra: icechunk
|
|
43
|
+
Requires-Dist: icechunk>=2; extra == 'icechunk'
|
|
44
|
+
Provides-Extra: s3
|
|
45
|
+
Requires-Dist: boto3; extra == 's3'
|
|
46
|
+
Description-Content-Type: text/markdown
|
|
47
|
+
|
|
48
|
+
# acmadDL
|
|
49
|
+
|
|
50
|
+
An API for fetching climate, environmental, and contextual datasets
|
|
51
|
+
|
|
52
|
+
acmadDL is ACCORD's data adapter layer. A single `fetch()` call retrieves data from many different providers (Copernicus CDS, the ECMWF Data Store, OPeNDAP, HTTP, S3, and others) and returns it as a normalized xarray dataset with canonical names, units, and coordinates. Data stays at the source; acmadDL does not host a central copy of anything. Adding a new dataset or provider is a catalog and adapter change, not a rewrite of your workflow.
|
|
53
|
+
|
|
54
|
+
## Installation
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install acmadDL
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The distribution is published as `acmadDL`; the import name is `acmaddl`. acmadDL requires Python 3.12 or newer.
|
|
61
|
+
|
|
62
|
+
Most CDS-based products (`c3s/*`, `obs/era5`) need CDS or ECMWF Data Store credentials; see [CDS / ECDS setup](#cds--ecds-setup).
|
|
63
|
+
|
|
64
|
+
## Core API
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
import acmaddl
|
|
68
|
+
|
|
69
|
+
ds = acmaddl.fetch(
|
|
70
|
+
product="nmme/cfsv2",
|
|
71
|
+
variable="precip",
|
|
72
|
+
init="2025-02",
|
|
73
|
+
target="MAM",
|
|
74
|
+
region=[-12, 6, 28, 42],
|
|
75
|
+
hindcast=(1993, 2016),
|
|
76
|
+
verbose=True,
|
|
77
|
+
progress=True,
|
|
78
|
+
)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
You pass a canonical `product` and `variable` plus optional temporal and spatial selectors. You get back a CF-aligned xarray dataset, ready for analysis or modeling. Results are returned in memory by default, or written to a local path or S3.
|
|
82
|
+
|
|
83
|
+
Verify an install and list what is available:
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
import acmaddl
|
|
87
|
+
acmaddl.check_all_products() # config checks for every product
|
|
88
|
+
acmaddl.catalog.list_products() # list product ids
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Normalized coordinates
|
|
92
|
+
|
|
93
|
+
Every dataset comes back with canonical coordinate names regardless of the upstream source:
|
|
94
|
+
|
|
95
|
+
| Coordinate | Applies to | Description |
|
|
96
|
+
|------------|-----------|-------------|
|
|
97
|
+
| `lat`, `lon` | all products | Spatial axes (latitude ascending) |
|
|
98
|
+
| `time` | observations / reanalysis | Monthly time axis (`datetime64`) |
|
|
99
|
+
| `init_time` | forecasts | Initialization time (`datetime64`) |
|
|
100
|
+
| `lead_time` | forecasts | Lead time (numeric, units vary by source) |
|
|
101
|
+
| `member` | forecasts | Ensemble member index |
|
|
102
|
+
|
|
103
|
+
Numeric time encodings (for example "months since 1960-01-01") are decoded to `datetime64` automatically.
|
|
104
|
+
|
|
105
|
+
### Region input
|
|
106
|
+
|
|
107
|
+
`region` accepts three forms:
|
|
108
|
+
|
|
109
|
+
| Form | Example | Behaviour |
|
|
110
|
+
|------|---------|-----------|
|
|
111
|
+
| bbox | `region=[-12, 6, 28, 42]` | `[lat_s, lat_n, lon_w, lon_e]` |
|
|
112
|
+
| shapefile | `region="kenya.shp"` | bounding box slices upstream; result masked to the polygon |
|
|
113
|
+
| geometry | `region=gdf.geometry` | shapely geometry or geopandas `GeoSeries`, same masking |
|
|
114
|
+
|
|
115
|
+
Shapefile and geometry inputs need the `geo` extra (`pip install 'acmadDL[geo]'`). The polygon is reprojected to EPSG:4326 and dissolved, so multi-feature files (for example an archipelago) clip correctly. Cells outside the polygon come back as `NaN`.
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
import acmaddl
|
|
119
|
+
|
|
120
|
+
# Clip to a country boundary; values outside Kenya become NaN.
|
|
121
|
+
ds = acmaddl.fetch(
|
|
122
|
+
product="nmme/cfsv2",
|
|
123
|
+
variable="precip",
|
|
124
|
+
init="2025-02",
|
|
125
|
+
target="MAM",
|
|
126
|
+
region="kenya.shp",
|
|
127
|
+
hindcast=(1993, 2016),
|
|
128
|
+
)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
By default a grid cell is included only if its centre lies inside the region (`boundary="center"`, the xarray/CDO/rasterio convention, and unbiased for area means). Pass `boundary="cover"` to keep every cell the region touches (matches rasterio's `all_touched=True`), which is useful for display or coarse grids where center-based selection can drop a country's thin tips. This applies to bbox and shapefile/geometry inputs alike.
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
ds = acmaddl.fetch(..., region="kenya.shp", boundary="cover")
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Note: polygons crossing the plus/minus 180 degree antimeridian are not yet handled (the derived bounding box spans the full longitude range). Split such geometries at the antimeridian before passing them in.
|
|
138
|
+
|
|
139
|
+
### Multiple predictor domains
|
|
140
|
+
|
|
141
|
+
Seasonal forecasting workflows often use two predictor domains from the same model, for example a large sea-surface-temperature domain and a smaller regional precipitation domain. Make one `fetch()` call per domain; there is no combined helper, because the domains differ in extent and variable.
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
import acmaddl
|
|
145
|
+
|
|
146
|
+
# SST predictor: large tropical domain
|
|
147
|
+
sst_predictor = acmaddl.fetch(
|
|
148
|
+
product="nmme/geoss2s", variable="sst",
|
|
149
|
+
init="2025-02", target="MAM",
|
|
150
|
+
region=[-20, 20, 30, 180], hindcast=(1993, 2016),
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
# Precipitation predictor: regional domain
|
|
154
|
+
prcp_predictor = acmaddl.fetch(
|
|
155
|
+
product="nmme/geoss2s", variable="precip",
|
|
156
|
+
init="2025-02", target="MAM",
|
|
157
|
+
region=[-20, 20, 10, 75], hindcast=(1993, 2016),
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
# Predictand: observations
|
|
161
|
+
predictand = acmaddl.fetch(
|
|
162
|
+
product="obs/chirps-v2-monthly", variable="precip",
|
|
163
|
+
target="MAM", region=[-12, 15, 22, 52], hindcast=(1993, 2016),
|
|
164
|
+
)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Health checks
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
import acmaddl
|
|
171
|
+
|
|
172
|
+
acmaddl.check_product("nmme/cfsv2") # one product, config only
|
|
173
|
+
acmaddl.check_all_products() # all products, config only
|
|
174
|
+
acmaddl.check_all_products(probe_remote=True) # also probe the live source
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Each result includes `product`, `adapter`, `healthy`, `kind`, `message`, and `checked_at`.
|
|
178
|
+
|
|
179
|
+
## Available products
|
|
180
|
+
|
|
181
|
+
How to read the tables. Hindcast is each model's fixed reforecast period, not a fetch cap: real-time forecasts run past it to the present. Forecast is the live-verified real-time availability, shown as `year–present` (ongoing) or `start–end (retired)` when the pinned system version was superseded (hindcasts still fetch, but no new forecasts issue). Members (F/H) are the real-time-forecast and reforecast ensemble sizes, which differ. `†` marks a deprecated access route. Full field conventions are documented at the top of [`src/acmaddl/catalog.yaml`](src/acmaddl/catalog.yaml).
|
|
182
|
+
|
|
183
|
+
Several C3S entries pin a system version whose real-time stream has ended (a 2026 forecast init returns no data); they still fetch hindcasts. CMCC's live stream has moved to `c3s/cmcc-sps4`. JMA and UKMO do not yet have an active-forecast entry on their current systems (JMA CPS4, UKMO 605).
|
|
184
|
+
|
|
185
|
+
Collapsed targeted seasonal precipitation (`year_index=True`, including
|
|
186
|
+
`assemble()`) is delivered in `mm` across NMME, C3S/CDS, and IRI products.
|
|
187
|
+
Lead-resolved fetches retain honest per-step units (usually `mm/day`). Monthly
|
|
188
|
+
rates are calendar-weighted and daily amounts are summed. Native ensemble spread is preserved;
|
|
189
|
+
`nmme/cfsv2` returns the 24 populated members and removes four structurally
|
|
190
|
+
empty trailing slots exposed by the upstream endpoint.
|
|
191
|
+
|
|
192
|
+
### Seasonal forecast, NMME
|
|
193
|
+
|
|
194
|
+
| Product | Model / system | Host | Adapter | Variables | Cadence | Members (F/H) | Hindcast | Forecast |
|
|
195
|
+
|---|---|---|---|---|---|---|---|---|
|
|
196
|
+
| `nmme/cansipsic4` | ECCC CanSIPS-IC4 | Columbia CCSR | `ccsr` | precip, temp, sst | monthly | 40 / 40 | 1990–2024 | 2024–present |
|
|
197
|
+
| `nmme/ccsm4` | NCAR/COLA CCSM4 | Columbia CCSR | `ccsr` | precip, temp, sst | monthly | 10 / 10 | 1982–2026 | 2014–present |
|
|
198
|
+
| `nmme/cesm1` | NCAR CESM1 | Columbia CCSR | `ccsr` | precip, temp, sst | monthly | 10 / 10 | 1982–2026 | 2017–present |
|
|
199
|
+
| `nmme/geoss2s` | NASA GEOS-S2S | Columbia CCSR | `ccsr` | precip, temp, sst | monthly | 10 / 4 | 1981–2017 | 2019–present |
|
|
200
|
+
| `nmme/spear` | GFDL SPEAR | Columbia CCSR | `ccsr` | precip, temp, sst | monthly | 30 / 15 | 1991–2020 | 2021–present |
|
|
201
|
+
| `nmme/spearb` | GFDL SPEARb | Columbia CCSR | `ccsr` | sst | monthly | 30 / 15 | 1991–2020 | 2021–present |
|
|
202
|
+
| `nmme/cfsv2` † | NCEP CFSv2 | IRI Data Library | `opendap` | precip, temp, sst | monthly | 28 / 28 | 1982–2010 | 2011–present |
|
|
203
|
+
|
|
204
|
+
### Seasonal forecast, C3S
|
|
205
|
+
|
|
206
|
+
| Product | Model / system | Host | Adapter | Variables | Cadence | Members (F/H) | Hindcast | Forecast |
|
|
207
|
+
|---|---|---|---|---|---|---|---|---|
|
|
208
|
+
| `c3s/cmcc` | CMCC SPSv3.5 (sys 35) | Copernicus CDS | `cds` | precip, temp, sst | monthly | 50 / 40 | 1993–2016 | 2020–2025 (retired) |
|
|
209
|
+
| `c3s/cmcc-daily` | CMCC SPSv3.5 (sys 35) | Copernicus CDS | `cds` | precip, temp, sst | daily | 50 / 40 | 1993–2016 | 2020–2025 (retired) |
|
|
210
|
+
| `c3s/cmcc-sps4` | CMCC SPS4 (sys 4) | Copernicus CDS | `cds` | precip, temp, sst | monthly | 50 / 30 | 1993–2024 | 2025–present |
|
|
211
|
+
| `c3s/cmcc-sps4-daily` | CMCC SPS4 (sys 4) | Copernicus CDS | `cds` | precip, temp, sst | daily | 50 / 30 | 1993–2024 | 2025–present |
|
|
212
|
+
| `c3s/dwd` | DWD GCFS2.2 (sys 22) | Copernicus CDS | `cds` | precip, temp, sst | monthly | 50 / 30 | 1993–2023 | 2023–present |
|
|
213
|
+
| `c3s/dwd-daily` | DWD GCFS2.2 (sys 22) | Copernicus CDS | `cds` | precip, temp, sst | daily | 50 / 30 | 1993–2023 | 2023–present |
|
|
214
|
+
| `c3s/dwd-gcfs21` | DWD GCFS2.1 (sys 21) | Copernicus CDS | `cds` | precip, temp, sst | monthly | 50 / 30 | 1993–2019 | 2020–2025 (retired) |
|
|
215
|
+
| `c3s/eccc-cansips` | ECCC GEM5-NEMO (sys 3) | Copernicus CDS | `cds` | precip, temp, sst | monthly | 10 / 10 | 1990–2020 | 2021–2024 (retired) |
|
|
216
|
+
| `c3s/eccc-cansipsv3` | ECCC CanESM5.1 (sys 4) | Copernicus CDS | `cds` | precip, temp, sst | monthly | 20 / 20 | 1980–2023 | 2024–present |
|
|
217
|
+
| `c3s/eccc-daily` | ECCC CanESM5.1 (sys 4) | Copernicus CDS | `cds` | precip, temp, sst | daily | 20 / 20 | 1980–2023 | 2024–present |
|
|
218
|
+
| `c3s/ecmwf` | ECMWF SEAS5 (sys 51) | Copernicus CDS | `cds` | precip, temp, sst | monthly | 51 / 25 | 1981–2016 | 2017–present |
|
|
219
|
+
| `c3s/ecmwf-monthly` | ECMWF SEAS5 (sys 51) | Copernicus CDS | `cds` | precip, temp, sst | monthly | 51 / 25 | 1981–2016 | 2017–present |
|
|
220
|
+
| `c3s/jma` | JMA CPS3 (sys 3) | Copernicus CDS | `cds` | precip, temp, sst | monthly | 155 / 10 | 1991–2020 | 2022–2026 (retired) |
|
|
221
|
+
| `c3s/jma-cps2` | JMA CPS2 (sys 2) | Copernicus CDS | `cds` | precip, temp, sst | monthly | 13 / 10 | 1981–2016 | 2015–2022 (retired) |
|
|
222
|
+
| `c3s/meteofrance` | Météo-France Sys 9 | Copernicus CDS | `cds` | precip, temp, sst | monthly | 51 / 31 | 1993–2024 | 2025–present |
|
|
223
|
+
| `c3s/meteofrance-daily` | Météo-France Sys 9 | Copernicus CDS | `cds` | precip, temp, sst | daily | 51 / 31 | 1993–2024 | 2025–present |
|
|
224
|
+
| `c3s/ukmo` | UKMO GloSea6 GC3.2 (sys 604) | Copernicus CDS | `cds` | precip, temp, sst | monthly | 62 / 28 | 1993–2016 | 2025–2026 (retired) |
|
|
225
|
+
| `c3s/ukmo-daily` | UKMO GloSea6 GC3.2 (sys 604) | Copernicus CDS | `cds` | precip, temp, sst | daily | 7 / 7 | 1993–2016 | 2025–2026 (retired) |
|
|
226
|
+
| `c3s/ecmwf-seas51c` † | - | IRI Data Library | `iridl` | precip, sst | monthly | 51 / 25 | 1993–2016 | - |
|
|
227
|
+
|
|
228
|
+
### Sub-seasonal forecast
|
|
229
|
+
|
|
230
|
+
| Product | Model / system | Host | Adapter | Variables | Cadence | Members (F/H) | Hindcast | Forecast |
|
|
231
|
+
|---|---|---|---|---|---|---|---|---|
|
|
232
|
+
| `c3s/ecmwf-s2s` | ECMWF S2S | ECMWF Data Store | `cds` | precip, sst | twice weekly | 50 / 11 | - | on-the-fly |
|
|
233
|
+
|
|
234
|
+
`c3s/ecmwf-s2s` is date-keyed: call it with `init="YYYY-MM-DD"` (the issuance date). Its reforecasts are generated on the fly, so there is no fixed hindcast window. It uses the ECMWF Data Store (`ecds.ecmwf.int`), a separate service from the Copernicus CDS; see [ECMWF Data Store (ECDS) setup](#ecmwf-data-store-ecds-setup).
|
|
235
|
+
|
|
236
|
+
### Reanalysis
|
|
237
|
+
|
|
238
|
+
| Product | Model / system | Host | Adapter | Variables | Cadence | Members (F/H) | Hindcast | Forecast |
|
|
239
|
+
|---|---|---|---|---|---|---|---|---|
|
|
240
|
+
| `obs/era5` | - | Copernicus CDS | `cds` | temp, precip, sst | monthly | - | 1940–2025 | - |
|
|
241
|
+
| `obs/era5-land-monthly` | - | Copernicus CDS | `cds` | precip, temp | monthly | - | 1950–2025 | - |
|
|
242
|
+
|
|
243
|
+
### Observation
|
|
244
|
+
|
|
245
|
+
| Product | Model / system | Host | Adapter | Variables | Cadence | Members (F/H) | Hindcast | Forecast |
|
|
246
|
+
|---|---|---|---|---|---|---|---|---|
|
|
247
|
+
| `obs/chirps-live-rhiza` | - | Rhiza/Sheerwater | `sheerwater` | precip | daily | - | - | - |
|
|
248
|
+
| `obs/chirps-v2-annual` | - | UCSB CHC | `http` | precip | annual | - | 1981–2024 | - |
|
|
249
|
+
| `obs/chirps-v2-daily` | - | UCSB CHC | `http` | precip | daily | - | 1981–2025 | - |
|
|
250
|
+
| `obs/chirps-v2-dekad` | - | UCSB CHC | `http` | precip | dekad | - | 1981–2025 | - |
|
|
251
|
+
| `obs/chirps-v2-dekadal-rhiza` | - | Rhiza/Sheerwater | `sheerwater` | precip | dekadal-rolling | - | 1997–2024 | - |
|
|
252
|
+
| `obs/chirps-v2-monthly` | - | UCSB CHC | `http` | precip | monthly | - | 1981–2025 | - |
|
|
253
|
+
| `obs/chirps-v2-pentad` | - | UCSB CHC | `http` | precip | pentad | - | 1981–2025 | - |
|
|
254
|
+
| `obs/chirps-v3-annual` | - | UCSB CHC | `http` | precip | annual | - | 1981–2025 | - |
|
|
255
|
+
| `obs/chirps-v3-daily` | - | UCSB CHC | `http` | precip | daily | - | 1998–2025 | - |
|
|
256
|
+
| `obs/chirps-v3-daily-rhiza` | - | Rhiza/Sheerwater | `sheerwater` | precip | daily | - | 2000–2024 | - |
|
|
257
|
+
| `obs/chirps-v3-dekad` | - | UCSB CHC | `http` | precip | dekad | - | 1981–2025 | - |
|
|
258
|
+
| `obs/chirps-v3-monthly` | - | UCSB CHC | `http` | precip | monthly | - | 1981–2025 | - |
|
|
259
|
+
| `obs/chirps-v3-pentad` | - | UCSB CHC | `http` | precip | pentad | - | 1981–2025 | - |
|
|
260
|
+
| `obs/ghcn` | - | Rhiza/Sheerwater | `sheerwater` | precip | monthly | - | 1981–2024 | - |
|
|
261
|
+
| `obs/imerg` | - | Rhiza/Sheerwater | `sheerwater` | precip | monthly | - | 2000–2024 | - |
|
|
262
|
+
|
|
263
|
+
For `nmme/cfsv2 †`, the model is still an active NMME member (live on CPC FTP); only its IRI Data Library access route is deprecated (IRIDL shutdown around October 2026), with no successor yet.
|
|
264
|
+
|
|
265
|
+
Output is always NetCDF (extensible to Zarr and GeoTIFF).
|
|
266
|
+
|
|
267
|
+
## CDS / ECDS setup
|
|
268
|
+
|
|
269
|
+
acmadDL's `cds` adapter talks to two distinct ECMWF endpoints, which are separate services with separate accounts, API keys, and licence-acceptance flows:
|
|
270
|
+
|
|
271
|
+
- Copernicus Climate Data Store (`cds.climate.copernicus.eu`): most `c3s/*` products and `obs/era5`.
|
|
272
|
+
- ECMWF Data Store (`ecds.ecmwf.int`): the newer service, currently used by `c3s/ecmwf-s2s`.
|
|
273
|
+
|
|
274
|
+
Each product's catalog entry selects its endpoint. You need credentials and accepted licences for each endpoint you fetch from.
|
|
275
|
+
|
|
276
|
+
### Copernicus CDS setup
|
|
277
|
+
|
|
278
|
+
For Copernicus CDS products (all `c3s/*` except `c3s/ecmwf-s2s`, plus `obs/era5`):
|
|
279
|
+
|
|
280
|
+
1. Create a CDS account and API key at <https://cds.climate.copernicus.eu>.
|
|
281
|
+
2. Add credentials to `~/.cdsapirc`:
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
cat > ~/.cdsapirc << 'EOF'
|
|
285
|
+
url: https://cds.climate.copernicus.eu/api
|
|
286
|
+
key: <YOUR-CDS-API-KEY>
|
|
287
|
+
EOF
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
3. Accept the required dataset licences in the CDS web UI before your first download. Each dataset page has a "Terms of use" section you tick once per account. If `acmaddl.fetch()` fails with a 403, the error names the dataset(s) still missing acceptance.
|
|
291
|
+
|
|
292
|
+
### ECMWF Data Store (ECDS) setup
|
|
293
|
+
|
|
294
|
+
Required for `c3s/ecmwf-s2s` (and any future product whose catalog entry uses `cds_url: "https://ecds.ecmwf.int/api"`). ECDS is a separate service; you cannot reuse Copernicus CDS credentials.
|
|
295
|
+
|
|
296
|
+
1. Create an ECMWF account at <https://www.ecmwf.int/>, log in to <https://ecds.ecmwf.int/>, and copy your API key from your profile settings.
|
|
297
|
+
2. Point `cdsapi` at the ECDS endpoint. If you only use ECDS, the simplest setup is to replace `~/.cdsapirc`:
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
cat > ~/.cdsapirc << 'EOF'
|
|
301
|
+
url: https://ecds.ecmwf.int/api
|
|
302
|
+
key: <YOUR-ECDS-API-KEY>
|
|
303
|
+
EOF
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
If you also use the Copernicus CDS, keep one endpoint in `~/.cdsapirc` and pass the other via the `CDSAPI_URL` / `CDSAPI_KEY` environment variables per session.
|
|
307
|
+
3. Accept both layers of ECDS licences (ECDS returns 403 until both are accepted):
|
|
308
|
+
- The site-wide Terms of Use, accepted once per account from the ECDS profile settings.
|
|
309
|
+
- The dataset licence, ticked on the dataset's own page. For S2S: <https://ecds.ecmwf.int/datasets/s2s-forecasts?tab=download#manage-licences>. Other datasets follow the same `https://ecds.ecmwf.int/datasets/<dataset-id>?tab=download#manage-licences` pattern.
|
|
310
|
+
|
|
311
|
+
As with the Copernicus CDS, a skipped licence produces a 403 that names exactly which licence is missing.
|
|
312
|
+
4. Test the connection:
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
uv run pytest tests/test_integration.py::test_fetch_c3s_ecmwf_s2s_precip -v
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
## Cache configuration
|
|
319
|
+
|
|
320
|
+
acmadDL caches adapter downloads locally using [Nuthatch](https://github.com/rhiza-research/nuthatch). Cache files live in `~/.nuthatch/acmaddl` by default (configured in `pyproject.toml`).
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
acmaddl cache list # inspect the cache
|
|
324
|
+
acmaddl cache clear # clear everything
|
|
325
|
+
acmaddl cache clear --product nmme/cfsv2 # clear one product (with confirmation)
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## Development setup
|
|
329
|
+
|
|
330
|
+
```bash
|
|
331
|
+
git clone https://github.com/ACMAD-Niamey/acmadDL.git
|
|
332
|
+
cd acmadDL
|
|
333
|
+
uv sync
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## Relationship to DeepScale
|
|
337
|
+
|
|
338
|
+
acmadDL handles ingestion and normalization; [DeepScale](https://github.com/accord-research/deepscale) handles downscaling and skill evaluation. Their interface is standardized xarray.
|