CMIP6 — API reference#
CMIP6 climate-projections data source subpackage — earthlens.cmip6.
Background, the facet request shape, and the config + curated-vocabulary catalog
are covered under the other pages in this section; this page is the rendered
API.
earthlens.cmip6
#
CMIP6 climate-projections backend (Pangeo ARCO mirror on gs://cmip6).
Exposes the raw, full CMIP6 archive — every ScenarioMIP / CMIP experiment,
every ESM, on its native grid — as analysis-ready cloud Zarr on the open Pangeo
Google Cloud mirror (gs://cmip6), indexed by a plain consolidated-stores CSV
(no auth). This is the whole model x scenario x variable x member matrix, not
the single pre-downscaled product the gee backend exposes (NASA/GDDP-CMIP6)
nor the CHC-CMIP6 precipitation deltas the chc backend exposes.
A request is a CMIP6 facet tuple — source_id (model), experiment_id
(scenario), variable_id, table_id (+ optional member_id / grid_label /
version) — which the resolver maps to the matching zstore (gs://cmip6/...)
URI(s). The backend is file-writing: download() has pyramids open the Zarr
and write a bbox/time NetCDF subset, returning the list[Path]. earthlens never
imports xarray / zarr / gcsfs — pyramids owns the read (via GDAL's /vsigs/
multidim driver, read anonymously; no gcsfs needed).
Public surface (re-exported from this package):
- :class:
CMIP6— the backend; instantiate with a date window, a bbox, and a facet tuple (source_id/experiment_id/variable_id/table_id), then call :meth:CMIP6.download. - :class:
Catalog— loader for the bundledcmip6_data_catalog.yaml(config + curated vocabulary). - :class:
Cmip6Variable/ :class:Experiment/ :class:Table/ :class:Source— one curated variable / experiment / table / source row. - :data:
CATALOG_PATH— path to the bundled YAML; monkey-patchable in tests. - :func:
clear_catalog_cache— empty the catalog parse cache. - :class:
StoreResolver/ :class:ResolvedStore— facet ->zstoreresolution over the consolidated-stores CSV.
Examples:
- Resolve a curated variable's metadata:
CMIP6
#
Bases: AbstractDataSource
CMIP6 climate-projections backend (raw archive on gs://cmip6).
Wraps the open Pangeo CMIP6 ARCO mirror so a user pulls a
model / scenario / variable / member subset of the raw CMIP6 archive through
the same download() shape every other earthlens backend uses. The output is
one gridded NetCDF per resolved store.
Attributes:
| Name | Type | Description |
|---|---|---|
OUTPUT_KIND |
OutputKind
|
|
Source code in libs/providers/atmosphere/src/earthlens/cmip6/backend.py
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 | |
__init__(start, end, *, source_id=None, experiment_id=None, variable_id=None, table_id=None, lat_lim=None, lon_lim=None, member_id=None, grid_label=None, version='latest', activity_id=None, whole_time=False, temporal_resolution='monthly', path=None, fmt='%Y-%m-%d', catalog=None, resolver=None)
#
Initialise a CMIP6 backend instance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start
|
str
|
Inclusive start of the date window (parsed with |
required |
end
|
str
|
Inclusive end of the date window. |
required |
source_id
|
str | None
|
Model key ( |
None
|
experiment_id
|
str | None
|
Scenario / experiment ( |
None
|
variable_id
|
str | None
|
The CMIP6 variable to fetch ( |
None
|
table_id
|
str | None
|
The MIP table ( |
None
|
lat_lim
|
list[float] | None
|
|
None
|
lon_lim
|
list[float] | None
|
|
None
|
member_id
|
str | None
|
Variant label; |
None
|
grid_label
|
str | None
|
Grid label ( |
None
|
version
|
str
|
|
'latest'
|
activity_id
|
str | None
|
MIP the experiment belongs to; |
None
|
whole_time
|
bool
|
Skip the date-window time subset and write the whole
series (warned). Defaults to |
False
|
temporal_resolution
|
str
|
Advisory cadence label (fixed by |
'monthly'
|
path
|
Path | str | None
|
Output directory for the written NetCDFs. |
None
|
fmt
|
str
|
|
'%Y-%m-%d'
|
catalog
|
Catalog | None
|
Optional pre-built :class: |
None
|
resolver
|
StoreResolver | None
|
Optional pre-built
:class: |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If a required facet ( |
Source code in libs/providers/atmosphere/src/earthlens/cmip6/backend.py
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | |
download(progress_bar=True)
#
Fetch the requested CMIP6 subset(s) and return the written paths.
Runs the cheap :meth:_search (facet -> zstore resolution) then
:meth:_fetch, which writes one bbox/time NetCDF subset per resolved
store.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
progress_bar
|
bool
|
Show a per-store progress bar. Defaults to |
True
|
Returns:
| Type | Description |
|---|---|
list[Path]
|
list[Path]: The written NetCDF paths, one per resolved store (never empty — a facet tuple that matches no store raises rather than returning an empty list). |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the facet tuple matches no store. |
Source code in libs/providers/atmosphere/src/earthlens/cmip6/backend.py
terms_note()
#
Return the attribution note for the requested source model.
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
The per-model |
Source code in libs/providers/atmosphere/src/earthlens/cmip6/backend.py
Catalog
#
Bases: AbstractCatalog
Config + curated-vocabulary catalog for the CMIP6 backend.
Reads the bundled cmip6_data_catalog.yaml (shipped as package data) and
exposes its variables: block as a map of :class:Cmip6Variable rows keyed
by variable_id under the inherited :attr:datasets field, plus parallel
:attr:experiments, :attr:tables, and :attr:sources maps and the
resolution config (:attr:csv_url, :attr:bucket, :attr:facet_columns,
:attr:default_member_id, :attr:default_version). Instantiate with no
arguments (Catalog()); :func:model_post_init loads and validates the YAML
in one pass and caches it by (path, mtime).
Attributes:
| Name | Type | Description |
|---|---|---|
csv_url |
str
|
URL of the consolidated-stores CSV (the full per-store index). |
bucket |
str
|
The public GCS bucket the |
facet_columns |
list[str]
|
The CSV facet columns, in file order. |
default_member_id |
str
|
Member label applied when a request omits it. |
default_version |
str
|
Version-selection policy ( |
default_terms_note |
str
|
Attribution fallback for an uncurated source. |
datasets |
dict[str, Cmip6Variable]
|
Map from |
experiments |
dict[str, Experiment]
|
Map from |
tables |
dict[str, Table]
|
Map from |
sources |
dict[str, Source]
|
Map from |
Examples:
- List curated variables and resolve one:
- An unknown variable raises with a did-you-mean hint:
Source code in libs/providers/atmosphere/src/earthlens/cmip6/catalog.py
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 | |
get_catalog()
#
Return the curated variable map (satisfies the abstract contract).
Returns:
| Type | Description |
|---|---|
dict[str, Cmip6Variable]
|
dict[str, Cmip6Variable]: Same object as :attr: |
Source code in libs/providers/atmosphere/src/earthlens/cmip6/catalog.py
get_experiment(key)
#
Return the :class:Experiment for key, with a did-you-mean hint.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
An |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Experiment |
Experiment
|
The matching experiment row. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in libs/providers/atmosphere/src/earthlens/cmip6/catalog.py
get_source(key)
#
Return the :class:Source for key, with a did-you-mean hint.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
A |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Source |
Source
|
The matching source row. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in libs/providers/atmosphere/src/earthlens/cmip6/catalog.py
get_table(key)
#
Return the :class:Table for key, with a did-you-mean hint.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
A |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Table |
Table
|
The matching table row. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in libs/providers/atmosphere/src/earthlens/cmip6/catalog.py
load(catalog_path=None)
classmethod
#
Read and validate the CMIP6 catalog from disk (cached).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
catalog_path
|
Path | None
|
Path to the catalog YAML. Defaults to the module-level
:data: |
None
|
Returns:
| Type | Description |
|---|---|
Catalog
|
A fully-populated :class: |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in libs/providers/atmosphere/src/earthlens/cmip6/catalog.py
model_post_init(__context)
#
Auto-load the bundled catalog when no variables were supplied.
Catalog() with no args reads :data:CATALOG_PATH (cached by
(path, mtime)); passing datasets=... skips the disk read (used in
tests). Either way the available_datasets index is derived from the
loaded variable map.
Raises:
| Type | Description |
|---|---|
ValueError
|
Propagated from :meth: |
Source code in libs/providers/atmosphere/src/earthlens/cmip6/catalog.py
terms_note(source_id)
#
Return the attribution note for source_id.
Falls back to :attr:default_terms_note for an uncurated source (or a
curated one with no per-model note).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source_id
|
str
|
The model key ( |
required |
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
The per-model |
Source code in libs/providers/atmosphere/src/earthlens/cmip6/catalog.py
Cmip6Variable
#
Bases: BaseModel
One curated CMIP6 variable row (the variable_id leaf).
A frozen value object with descriptive metadata only — CMIP6 variables carry
no request-shaping parameters; the facet tuple selects the store and pyramids
reads the array. Curated rows are optional: an uncurated variable_id still
resolves against the CSV, it just lacks these labels.
Attributes:
| Name | Type | Description |
|---|---|---|
units |
str
|
CMIP6 CMOR unit ( |
long_name |
str
|
Human-readable description used in docs and logs. |
realm |
str
|
Modelling realm the variable belongs to ( |
Examples:
- Build a variable row directly:
Source code in libs/providers/atmosphere/src/earthlens/cmip6/catalog.py
Experiment
#
Bases: BaseModel
One curated CMIP6 experiment (scenario / diagnostic) row.
Attributes:
| Name | Type | Description |
|---|---|---|
activity_id |
str
|
The MIP the experiment belongs to ( |
description |
str
|
Human-readable summary. |
Examples:
- Inspect an experiment's activity:
Source code in libs/providers/atmosphere/src/earthlens/cmip6/catalog.py
ResolvedStore
dataclass
#
One CMIP6 Zarr store resolved from a facet tuple.
Carries the zstore URI plus the facet values that identify it, so the
backend can name the output file and log the provenance without re-querying
the CSV.
Attributes:
| Name | Type | Description |
|---|---|---|
zstore |
str
|
The |
source_id |
str
|
Model that produced the store. |
experiment_id |
str
|
Scenario / diagnostic experiment. |
variable_id |
str
|
The CMIP6 variable. |
table_id |
str
|
The MIP table (realm x cadence). |
member_id |
str
|
The variant label ( |
grid_label |
str
|
Grid label ( |
version |
str
|
Data-publication version (an integer date, as a string). |
activity_id |
str
|
The MIP the experiment belongs to. |
Examples:
- Build one directly:
>>> from earthlens.cmip6.resolver import ResolvedStore >>> s = ResolvedStore( ... zstore="gs://cmip6/CMIP6/ScenarioMIP/.../tas/gn/v20190101/", ... source_id="CanESM5", experiment_id="ssp585", variable_id="tas", ... table_id="Amon", member_id="r1i1p1f1", grid_label="gn", ... version="20190101", activity_id="ScenarioMIP", ... ) >>> s.variable_id 'tas'
Source code in libs/providers/atmosphere/src/earthlens/cmip6/resolver.py
slug
property
#
A filesystem-safe stem identifying this store.
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
|
Source
#
Bases: BaseModel
One curated CMIP6 source-model (GCM) row.
Attributes:
| Name | Type | Description |
|---|---|---|
institution_id |
str
|
The modelling centre that produced the model. |
terms_note |
str
|
Any per-model licence / attribution nuance (most CMIP6 models are CC BY 4.0, cited via the source GCM). |
description |
str
|
Optional human-readable summary. |
Examples:
- Read a source's institution:
Source code in libs/providers/atmosphere/src/earthlens/cmip6/catalog.py
StoreResolver
#
Resolve CMIP6 facet tuples to zstore URIs over the consolidated CSV.
Fetches + caches the CSV once, then filters it per request. Construct with
the catalog's csv_url + facet_columns; inject a frame= or cache_path=
to run offline.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
csv_url
|
str
|
URL of the consolidated-stores CSV. |
required |
facet_columns
|
list[str]
|
The CSV facet column names (from the catalog), kept as
schema documentation; |
required |
cache_path
|
Path | str | None
|
Where to cache the downloaded CSV. Defaults to
:func: |
None
|
frame
|
DataFrame | None
|
A pre-loaded |
None
|
timeout
|
float
|
Per-request network timeout, in seconds. |
120.0
|
Source code in libs/providers/atmosphere/src/earthlens/cmip6/resolver.py
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 | |
frame
property
#
The consolidated-stores table, loaded + cached on first access.
Returns:
| Type | Description |
|---|---|
DataFrame
|
pandas.DataFrame: The full store index. |
resolve(*, source_id, experiment_id, variable_id, table_id, member_id=None, grid_label=None, version='latest', activity_id=None)
#
Resolve a facet tuple to the matching zstore store(s).
Filters the CSV by every pinned facet (unset facets fan out), then
reduces version="latest" to the newest publication per store. Returns
one :class:ResolvedStore per surviving row.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source_id
|
str
|
Model (required). |
required |
experiment_id
|
str
|
Scenario / experiment (required). |
required |
variable_id
|
str
|
Variable (required). |
required |
table_id
|
str
|
MIP table (required). |
required |
member_id
|
str | None
|
Variant label; |
None
|
grid_label
|
str | None
|
Grid label; |
None
|
version
|
str
|
|
'latest'
|
activity_id
|
str | None
|
MIP; |
None
|
Returns:
| Type | Description |
|---|---|
list[ResolvedStore]
|
list[ResolvedStore]: One entry per matching store. For
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If no store matches; the message names the facet that eliminated every row and lists the values that were available. |
Source code in libs/providers/atmosphere/src/earthlens/cmip6/resolver.py
Table
#
Bases: BaseModel
One curated CMIP6 MIP-table row (a realm x cadence bundle).
Attributes:
| Name | Type | Description |
|---|---|---|
realm |
str
|
Modelling realm ( |
cadence |
str
|
Output cadence ( |
description |
str
|
Human-readable summary. |
Examples:
- Read a table's cadence:
Source code in libs/providers/atmosphere/src/earthlens/cmip6/catalog.py
earthlens.cmip6.backend
#
Backend that fetches raw CMIP6 climate projections from the Pangeo ARCO mirror.
CMIP6(AbstractDataSource) exposes the full raw CMIP6 archive — every
ScenarioMIP / CMIP experiment, every ESM, on its native grid — as analysis-ready
Zarr on the open gs://cmip6 Google Cloud bucket (Pangeo), indexed by a plain
consolidated-stores CSV with no auth. This is the whole model x scenario x
variable x member matrix, unlike the single pre-downscaled NASA/GDDP-CMIP6
product the gee backend exposes or the CHC-CMIP6 precipitation deltas the chc
backend exposes.
A request is a CMIP6 facet tuple — source_id (model), experiment_id
(scenario), variable_id, table_id (+ optional member_id / grid_label /
version). :meth:_search resolves it against the CSV
(:class:~earthlens.cmip6.resolver.StoreResolver) to the matching zstore
URI(s) — a tuple that pins fewer facets fans out, one output per store.
:meth:_fetch then has pyramids open each store and write a bbox/time NetCDF
subset (:mod:earthlens.cmip6.accessor): the [start, end] window maps to an
integer time-index range, the lat_lim/lon_lim box crops the grid, and only
the requested cells are fetched. earthlens never imports xarray / zarr /
gcsfs — pyramids owns the read (GDAL /vsigs/, anonymous).
The archive is on each model's native grid and stores are large, so a subset is
the default; a whole-grid download (lat_lim/lon_lim left at whole-Earth) is
allowed but warned. Aggregation (aggregate=) is not supported — the written
NetCDFs can be aggregated separately.
CMIP6
#
Bases: AbstractDataSource
CMIP6 climate-projections backend (raw archive on gs://cmip6).
Wraps the open Pangeo CMIP6 ARCO mirror so a user pulls a
model / scenario / variable / member subset of the raw CMIP6 archive through
the same download() shape every other earthlens backend uses. The output is
one gridded NetCDF per resolved store.
Attributes:
| Name | Type | Description |
|---|---|---|
OUTPUT_KIND |
OutputKind
|
|
Source code in libs/providers/atmosphere/src/earthlens/cmip6/backend.py
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 | |
__init__(start, end, *, source_id=None, experiment_id=None, variable_id=None, table_id=None, lat_lim=None, lon_lim=None, member_id=None, grid_label=None, version='latest', activity_id=None, whole_time=False, temporal_resolution='monthly', path=None, fmt='%Y-%m-%d', catalog=None, resolver=None)
#
Initialise a CMIP6 backend instance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start
|
str
|
Inclusive start of the date window (parsed with |
required |
end
|
str
|
Inclusive end of the date window. |
required |
source_id
|
str | None
|
Model key ( |
None
|
experiment_id
|
str | None
|
Scenario / experiment ( |
None
|
variable_id
|
str | None
|
The CMIP6 variable to fetch ( |
None
|
table_id
|
str | None
|
The MIP table ( |
None
|
lat_lim
|
list[float] | None
|
|
None
|
lon_lim
|
list[float] | None
|
|
None
|
member_id
|
str | None
|
Variant label; |
None
|
grid_label
|
str | None
|
Grid label ( |
None
|
version
|
str
|
|
'latest'
|
activity_id
|
str | None
|
MIP the experiment belongs to; |
None
|
whole_time
|
bool
|
Skip the date-window time subset and write the whole
series (warned). Defaults to |
False
|
temporal_resolution
|
str
|
Advisory cadence label (fixed by |
'monthly'
|
path
|
Path | str | None
|
Output directory for the written NetCDFs. |
None
|
fmt
|
str
|
|
'%Y-%m-%d'
|
catalog
|
Catalog | None
|
Optional pre-built :class: |
None
|
resolver
|
StoreResolver | None
|
Optional pre-built
:class: |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If a required facet ( |
Source code in libs/providers/atmosphere/src/earthlens/cmip6/backend.py
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | |
download(progress_bar=True)
#
Fetch the requested CMIP6 subset(s) and return the written paths.
Runs the cheap :meth:_search (facet -> zstore resolution) then
:meth:_fetch, which writes one bbox/time NetCDF subset per resolved
store.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
progress_bar
|
bool
|
Show a per-store progress bar. Defaults to |
True
|
Returns:
| Type | Description |
|---|---|
list[Path]
|
list[Path]: The written NetCDF paths, one per resolved store (never empty — a facet tuple that matches no store raises rather than returning an empty list). |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the facet tuple matches no store. |
Source code in libs/providers/atmosphere/src/earthlens/cmip6/backend.py
terms_note()
#
Return the attribution note for the requested source model.
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
The per-model |
Source code in libs/providers/atmosphere/src/earthlens/cmip6/backend.py
earthlens.cmip6.catalog
#
Config + curated-vocabulary catalog for the CMIP6 backend.
Hosts :class:Catalog, the pydantic-backed reader for the bundled
cmip6_data_catalog.yaml. CMIP6 is addressed by a facet tuple
(source_id, experiment_id, variable_id, table_id, plus optional
member_id / grid_label / version), and the per-store index — one Zarr
store per facet combination — is far too large to inline (~515k rows). That
index is the consolidated-stores CSV at :attr:Catalog.csv_url, fetched and
cached by :mod:earthlens.cmip6.resolver; this catalog holds only the config
(CSV URL, bucket, facet columns, defaults) plus a curated vocabulary of the
common variables / experiments / tables / sources used for output metadata,
docs, and did-you-mean hints.
The curated variables: block is exposed under the inherited
:attr:~earthlens.base.AbstractCatalog.datasets field, so a variable resolves
with cat["tas"] / "tas" in cat / the did-you-mean error for free;
experiments: / tables: / sources: hang off parallel maps. Resolution
itself runs against the full CSV, so an uncurated facet still downloads — the
curated rows only enrich metadata and error messages.
:data:CATALOG_PATH is the path to the bundled YAML;
:func:clear_catalog_cache empties the (path, mtime) parse cache.
Catalog
#
Bases: AbstractCatalog
Config + curated-vocabulary catalog for the CMIP6 backend.
Reads the bundled cmip6_data_catalog.yaml (shipped as package data) and
exposes its variables: block as a map of :class:Cmip6Variable rows keyed
by variable_id under the inherited :attr:datasets field, plus parallel
:attr:experiments, :attr:tables, and :attr:sources maps and the
resolution config (:attr:csv_url, :attr:bucket, :attr:facet_columns,
:attr:default_member_id, :attr:default_version). Instantiate with no
arguments (Catalog()); :func:model_post_init loads and validates the YAML
in one pass and caches it by (path, mtime).
Attributes:
| Name | Type | Description |
|---|---|---|
csv_url |
str
|
URL of the consolidated-stores CSV (the full per-store index). |
bucket |
str
|
The public GCS bucket the |
facet_columns |
list[str]
|
The CSV facet columns, in file order. |
default_member_id |
str
|
Member label applied when a request omits it. |
default_version |
str
|
Version-selection policy ( |
default_terms_note |
str
|
Attribution fallback for an uncurated source. |
datasets |
dict[str, Cmip6Variable]
|
Map from |
experiments |
dict[str, Experiment]
|
Map from |
tables |
dict[str, Table]
|
Map from |
sources |
dict[str, Source]
|
Map from |
Examples:
- List curated variables and resolve one:
- An unknown variable raises with a did-you-mean hint:
Source code in libs/providers/atmosphere/src/earthlens/cmip6/catalog.py
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 | |
get_catalog()
#
Return the curated variable map (satisfies the abstract contract).
Returns:
| Type | Description |
|---|---|
dict[str, Cmip6Variable]
|
dict[str, Cmip6Variable]: Same object as :attr: |
Source code in libs/providers/atmosphere/src/earthlens/cmip6/catalog.py
get_experiment(key)
#
Return the :class:Experiment for key, with a did-you-mean hint.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
An |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Experiment |
Experiment
|
The matching experiment row. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in libs/providers/atmosphere/src/earthlens/cmip6/catalog.py
get_source(key)
#
Return the :class:Source for key, with a did-you-mean hint.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
A |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Source |
Source
|
The matching source row. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in libs/providers/atmosphere/src/earthlens/cmip6/catalog.py
get_table(key)
#
Return the :class:Table for key, with a did-you-mean hint.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
A |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Table |
Table
|
The matching table row. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in libs/providers/atmosphere/src/earthlens/cmip6/catalog.py
load(catalog_path=None)
classmethod
#
Read and validate the CMIP6 catalog from disk (cached).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
catalog_path
|
Path | None
|
Path to the catalog YAML. Defaults to the module-level
:data: |
None
|
Returns:
| Type | Description |
|---|---|
Catalog
|
A fully-populated :class: |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in libs/providers/atmosphere/src/earthlens/cmip6/catalog.py
model_post_init(__context)
#
Auto-load the bundled catalog when no variables were supplied.
Catalog() with no args reads :data:CATALOG_PATH (cached by
(path, mtime)); passing datasets=... skips the disk read (used in
tests). Either way the available_datasets index is derived from the
loaded variable map.
Raises:
| Type | Description |
|---|---|
ValueError
|
Propagated from :meth: |
Source code in libs/providers/atmosphere/src/earthlens/cmip6/catalog.py
terms_note(source_id)
#
Return the attribution note for source_id.
Falls back to :attr:default_terms_note for an uncurated source (or a
curated one with no per-model note).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source_id
|
str
|
The model key ( |
required |
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
The per-model |
Source code in libs/providers/atmosphere/src/earthlens/cmip6/catalog.py
Cmip6Variable
#
Bases: BaseModel
One curated CMIP6 variable row (the variable_id leaf).
A frozen value object with descriptive metadata only — CMIP6 variables carry
no request-shaping parameters; the facet tuple selects the store and pyramids
reads the array. Curated rows are optional: an uncurated variable_id still
resolves against the CSV, it just lacks these labels.
Attributes:
| Name | Type | Description |
|---|---|---|
units |
str
|
CMIP6 CMOR unit ( |
long_name |
str
|
Human-readable description used in docs and logs. |
realm |
str
|
Modelling realm the variable belongs to ( |
Examples:
- Build a variable row directly:
Source code in libs/providers/atmosphere/src/earthlens/cmip6/catalog.py
Experiment
#
Bases: BaseModel
One curated CMIP6 experiment (scenario / diagnostic) row.
Attributes:
| Name | Type | Description |
|---|---|---|
activity_id |
str
|
The MIP the experiment belongs to ( |
description |
str
|
Human-readable summary. |
Examples:
- Inspect an experiment's activity:
Source code in libs/providers/atmosphere/src/earthlens/cmip6/catalog.py
Source
#
Bases: BaseModel
One curated CMIP6 source-model (GCM) row.
Attributes:
| Name | Type | Description |
|---|---|---|
institution_id |
str
|
The modelling centre that produced the model. |
terms_note |
str
|
Any per-model licence / attribution nuance (most CMIP6 models are CC BY 4.0, cited via the source GCM). |
description |
str
|
Optional human-readable summary. |
Examples:
- Read a source's institution:
Source code in libs/providers/atmosphere/src/earthlens/cmip6/catalog.py
Table
#
Bases: BaseModel
One curated CMIP6 MIP-table row (a realm x cadence bundle).
Attributes:
| Name | Type | Description |
|---|---|---|
realm |
str
|
Modelling realm ( |
cadence |
str
|
Output cadence ( |
description |
str
|
Human-readable summary. |
Examples:
- Read a table's cadence:
Source code in libs/providers/atmosphere/src/earthlens/cmip6/catalog.py
earthlens.cmip6.resolver
#
Facet -> zstore resolver over the CMIP6 consolidated-stores CSV.
The Pangeo CMIP6 ARCO index is a single flat CSV — one row per Zarr store,
keyed by the CMIP6 facets (source_id, experiment_id, variable_id,
table_id, member_id, grid_label, version, ...) with the store URI in the
zstore column. :class:StoreResolver fetches and caches that CSV (with
requests, read with pandas — both core), then filters it by a requested
facet tuple to the matching zstore URI(s).
The resolver is deliberately stateless and injectable: pass a pre-loaded
frame= or a local cache_path= to run with no network. On a miss it raises
a ValueError that names the facet which eliminated every row and lists the
values that were available — so a typo in a model or scenario name is easy to
fix.
No intake-esm (it would drag in xarray); no xarray / zarr / gcsfs
here — this module only resolves URIs. Opening the store is
:mod:earthlens.cmip6.accessor's job (pyramids).
ResolvedStore
dataclass
#
One CMIP6 Zarr store resolved from a facet tuple.
Carries the zstore URI plus the facet values that identify it, so the
backend can name the output file and log the provenance without re-querying
the CSV.
Attributes:
| Name | Type | Description |
|---|---|---|
zstore |
str
|
The |
source_id |
str
|
Model that produced the store. |
experiment_id |
str
|
Scenario / diagnostic experiment. |
variable_id |
str
|
The CMIP6 variable. |
table_id |
str
|
The MIP table (realm x cadence). |
member_id |
str
|
The variant label ( |
grid_label |
str
|
Grid label ( |
version |
str
|
Data-publication version (an integer date, as a string). |
activity_id |
str
|
The MIP the experiment belongs to. |
Examples:
- Build one directly:
>>> from earthlens.cmip6.resolver import ResolvedStore >>> s = ResolvedStore( ... zstore="gs://cmip6/CMIP6/ScenarioMIP/.../tas/gn/v20190101/", ... source_id="CanESM5", experiment_id="ssp585", variable_id="tas", ... table_id="Amon", member_id="r1i1p1f1", grid_label="gn", ... version="20190101", activity_id="ScenarioMIP", ... ) >>> s.variable_id 'tas'
Source code in libs/providers/atmosphere/src/earthlens/cmip6/resolver.py
slug
property
#
A filesystem-safe stem identifying this store.
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
|
StoreResolver
#
Resolve CMIP6 facet tuples to zstore URIs over the consolidated CSV.
Fetches + caches the CSV once, then filters it per request. Construct with
the catalog's csv_url + facet_columns; inject a frame= or cache_path=
to run offline.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
csv_url
|
str
|
URL of the consolidated-stores CSV. |
required |
facet_columns
|
list[str]
|
The CSV facet column names (from the catalog), kept as
schema documentation; |
required |
cache_path
|
Path | str | None
|
Where to cache the downloaded CSV. Defaults to
:func: |
None
|
frame
|
DataFrame | None
|
A pre-loaded |
None
|
timeout
|
float
|
Per-request network timeout, in seconds. |
120.0
|
Source code in libs/providers/atmosphere/src/earthlens/cmip6/resolver.py
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 | |
frame
property
#
The consolidated-stores table, loaded + cached on first access.
Returns:
| Type | Description |
|---|---|
DataFrame
|
pandas.DataFrame: The full store index. |
resolve(*, source_id, experiment_id, variable_id, table_id, member_id=None, grid_label=None, version='latest', activity_id=None)
#
Resolve a facet tuple to the matching zstore store(s).
Filters the CSV by every pinned facet (unset facets fan out), then
reduces version="latest" to the newest publication per store. Returns
one :class:ResolvedStore per surviving row.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source_id
|
str
|
Model (required). |
required |
experiment_id
|
str
|
Scenario / experiment (required). |
required |
variable_id
|
str
|
Variable (required). |
required |
table_id
|
str
|
MIP table (required). |
required |
member_id
|
str | None
|
Variant label; |
None
|
grid_label
|
str | None
|
Grid label; |
None
|
version
|
str
|
|
'latest'
|
activity_id
|
str | None
|
MIP; |
None
|
Returns:
| Type | Description |
|---|---|
list[ResolvedStore]
|
list[ResolvedStore]: One entry per matching store. For
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If no store matches; the message names the facet that eliminated every row and lists the values that were available. |
Source code in libs/providers/atmosphere/src/earthlens/cmip6/resolver.py
default_cache_path()
#
Return the default on-disk location for the cached CSV.
Resolved from the shared earthlens cache directory (set_cache_dir() /
EARTHLENS_CACHE). The CMIP6 CSV lands under a cmip6/ subdirectory.
Returns:
| Name | Type | Description |
|---|---|---|
Path |
Path
|
|
Source code in libs/providers/atmosphere/src/earthlens/cmip6/resolver.py
earthlens.cmip6.accessor
#
Thin pyramids accessor for the CMIP6 Zarr stores (the read boundary).
Everything that opens a gs://cmip6 Zarr store, windows it, and writes a NetCDF
subset lives here — the one place earthlens touches pyramids for CMIP6. earthlens
itself never imports xarray / zarr / gcsfs; pyramids reads the store through
GDAL's /vsigs/ multidimensional driver (no gcsfs needed), and this module only:
- rewrites a
gs://cmip6/<path>/zstoreURI to the GDALZARR:"/vsigs/..."form (:func:zstore_to_vsi); - forces anonymous GCS access with
GS_NO_SIGN_REQUESTaround every read (:func:anonymous_gcs) — pyramids'anon=Trueonly sets the AWS flag, and this machine may carry ambient GCS credentials, so the flag is set explicitly; - maps a CF
[start, end]date window to an integer time-index range (:func:resolve_time_window) — the gridded reader selects time by integer index, andLabeledDataset.select_timeis the public path that decodes CF time / non-standard calendars; - reads the gridded
(time, bbox)slice and writes it to NetCDF (:func:write_subset), a windowed read that fetches only the requested cells.
The pyramids reader classes are imported lazily behind an install-hint so the package imports (and the backend constructs) without a read ever happening.
anonymous_gcs()
#
Force anonymous GCS access for the duration of the with block.
Sets GS_NO_SIGN_REQUEST=YES so GDAL's /vsigs/ driver reads the public
gs://cmip6 bucket without signing — even when the environment carries GCS
credentials (e.g. a Google Earth Engine service account) — then restores the
prior value. The flag must stay live for the lazy data-chunk reads, not just
the open, so wrap the whole read + write.
Yields:
| Name | Type | Description |
|---|---|---|
None |
None
|
control to the |
Source code in libs/providers/atmosphere/src/earthlens/cmip6/accessor.py
resolve_time_window(zstore, variable, start=None, end=None, *, time_dim='time')
#
Map a CF [start, end] date window to an integer time-index range.
The gridded reader (:func:write_subset) selects time by integer index;
CMIP6 ARCO stores do not surface CF time units through GDAL's multidim path,
but LabeledDataset.select_time decodes the store's own time units +
calendar (so noleap / 360_day work). The half-open window is recovered
from public counts alone:
i0 = N - select_time(start=start).sizes[time](steps at or afterstart)i1 = select_time(end=end).sizes[time](steps at or beforeend)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
zstore
|
str
|
The |
required |
variable
|
str
|
The data variable to open (keeps the read light). |
required |
start
|
Any
|
Inclusive window start ( |
None
|
end
|
Any
|
Inclusive window end; |
None
|
time_dim
|
str
|
Name of the time dimension. |
'time'
|
Returns:
| Type | Description |
|---|---|
tuple[int, int] | None
|
tuple[int, int] | None: The half-open |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the window selects no timesteps. |
Source code in libs/providers/atmosphere/src/earthlens/cmip6/accessor.py
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | |
store_output_stem(store, start, end)
#
Compose a unique output-file stem for one resolved store + window.
The store version is folded in so two calls that pin different explicit
version= values for the same identity (or a CSV carrying duplicate
(identity, version) rows) write to distinct files instead of the second
silently overwriting the first.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
store
|
ResolvedStore
|
The resolved store (supplies the facet slug + version). |
required |
start
|
Any
|
Window start (its |
required |
end
|
Any
|
Window end. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
|
Source code in libs/providers/atmosphere/src/earthlens/cmip6/accessor.py
write_subset(zstore, variable, *, bbox, time, out_path, crs=4326)
#
Read a (variable, time, bbox) window of a store and write it to NetCDF.
Opens the resolved Zarr store through pyramids' NetCDF reader (GDAL
/vsigs/, anonymous) and writes the windowed slice — only the requested
cells are fetched. The read + write both run inside :func:anonymous_gcs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
zstore
|
str
|
The |
required |
variable
|
str
|
The data variable to read ( |
required |
bbox
|
tuple[float, float, float, float] | None
|
|
required |
time
|
int | tuple[int, int] | slice | None
|
Integer time selector ( |
required |
out_path
|
Path | str
|
Destination path for the written NetCDF. |
required |
crs
|
int | str
|
CRS of |
4326
|
Returns:
| Name | Type | Description |
|---|---|---|
Path |
Path
|
The written NetCDF path. |
Source code in libs/providers/atmosphere/src/earthlens/cmip6/accessor.py
zstore_to_vsi(zstore)
#
Rewrite a gs:// store URI to the GDAL ZARR:"/vsigs/..." form.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
zstore
|
str
|
A |
required |
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
The |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Examples:
- Rewrite a store URI: