eWaterCycle plugin: DestinE
Forcing for eWaterCycle from the DestinE Climate Digital Twin, read straight from the zarr stores that the Earth Data Hub serves.
Prerequisites
A DestinE account with the Data Access Policy upgrade, and an Earth Data Hub API key: log in at https://platform.destine.eu/, then Menu → Quota & API Keys.
Make the key available in one of two ways:
export EDH_API_KEY=<your-api-key>
or in ~/.netrc (~/_netrc on Windows), which survives across sessions:
machine api.earthdatahub.destine.eu
login edh
password <your-api-key>
If you would rather keep the key in a .env file, scripts/setup_env.py writes
one for you, leaves an existing key alone, and can ask the Hub whether the key is
actually accepted:
python scripts/setup_env.py # prompts if there is no key yet
python scripts/setup_env.py --check # and verify it against Earth Data Hub
Note that the library itself never reads .env — it looks at EDH_API_KEY and
then at ~/.netrc — so a .env still has to be loaded by whatever runs your
code. The script prints the usual ways.
Installation
Install alongside your eWaterCycle installation:
pip install ewatercycle-destine
Two forcing sources then become available:
from ewatercycle.forcing import sources
sources["DestinEForcing"] # gridded
sources["DestinELumpedMakkinkForcing"] # catchment-averaged
Each is the Makkink forcing of its own shape — DestinEForcing is a
DistributedMakkinkForcing, DestinELumpedMakkinkForcing is a
LumpedMakkinkForcing — so models that annotate their forcing field with those
types, HBV among them, accept them directly. They are siblings, not parent and
child, so a model that wants a grid cannot be handed a catchment average.
Two worked examples live in docs/:
destine_forcing.ipynb— the plugin end to end, lumped and distributed, historical and scenario.forcings_with_hbv.ipynb— the same HBV run on Caravan, ERA5, ERA5-Land and DestinE forcing, side by side.
Choosing a store
A store is addressed by three keys:
| key | values |
|---|---|
model |
IFS-NEMO, IFS-FESOM, ICON |
experiment |
hist (1990-2014), cont, SSP3-7.0 (2015-2049) |
variant |
standard, high-timeseries, high-maps |
The variants trade resolution against coverage, and they are not interchangeable:
| variant | resolution | variables | radiation |
|---|---|---|---|
standard (default) |
0.35° | 37 | yes (avg_sdswrf) |
high-timeseries |
0.044° | 7 | no |
high-maps |
0.044° | 7, chunked for maps | no |
Makkink potential evaporation is derived from radiation, so rsds and
evspsblpot are only available from standard. Asking a high-resolution
variant for either raises a ValueError rather than quietly giving you
something else.
Variables are named as eWaterCycle expects them: pr (kg m-2 s-1), tas (K),
rsds (W m-2) and evspsblpot (kg m-2 s-1). Hourly store data is aggregated
to daily means.
Lumped forcing
For a catchment-averaged time series, area-weighted by cos(latitude):
from pathlib import Path
from ewatercycle.forcing import sources
forcing = sources["DestinELumpedMakkinkForcing"].generate(
start_time="2000-01-01T00:00:00Z",
end_time="2000-12-31T00:00:00Z",
directory="./forcing/rhine_lumped",
shape=Path("Rhine.shp"),
model="IFS-FESOM",
experiment="hist",
)
forcing["pr"] # path to the precipitation file
forcing.to_xarray() # all variables in one dataset
Distributed forcing
For the grid, clipped to the catchment outline:
forcing = sources["DestinEForcing"].generate(
start_time="2015-01-01T00:00:00Z",
end_time="2015-12-31T00:00:00Z",
directory="./forcing/rhine_gridded",
shape=Path("Rhine.shp"),
variables=("pr", "tas"),
model="ICON",
experiment="SSP3-7.0",
variant="high-timeseries", # 0.044 degree, no radiation
)
Only the variables you ask for are written. Derived ones pull in what they
need: variables=("evspsblpot",) fetches tas and rsds but writes only
evspsblpot.
Reusing a forcing
generate() saves an ewatercycle_forcing.yaml next to the NetCDF files and
copies the shapefile in, all referenced by name. The directory can be moved or
shared, and read back with:
forcing = sources["DestinELumpedMakkinkForcing"].load("./forcing/rhine_lumped")
Development
pip install -e .[dev]
ruff check
mypy
pytest # no network
pytest -m integration # hits the real store, needs an API key
scripts/probe_store.py prints what a store really contains (variables, dims,
coordinate order, chunking), which is the quickest way to check the values this
plugin hard-codes against the catalogue.
License
ewatercycle-destine is distributed under the terms of the
Apache-2.0 license.
Metadata
Release files for ewatercycle-destine 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ewatercycle_destine-0.1.1.tar.gz | 753.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ewatercycle_destine-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 770.6 kB
Release files / ewatercycle_destine-0.1.1.tar.gz
| Download URL | ewatercycle_destine-0.1.1.tar.gz |
|---|---|
| Size | 753.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
514076c7422e1184357454741e068e7af961920f4ed4094d9123510eb3a19ef3
|
|
BLAKE2b-256 checksum How to use checksums |
2ea8d1809b8a7b9004ee12f1c05e5777b5972ae0c79a1945bb1500cf8d0b8c75
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.0
|
Release files / ewatercycle_destine-0.1.1-py3-none-any.whl
| Download URL | ewatercycle_destine-0.1.1-py3-none-any.whl |
|---|---|
| Size | 17.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
61e8ca7bb1b11bc8cd4004ffd7735084145351de1169250c439e850452ea21ca
|
|
BLAKE2b-256 checksum How to use checksums |
41f9ca3000c6f0da1610572667eec0e2f010d00ef502e195a97f3dd6628cb10f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.0
|