The Climate Impact Lab Downscaled Projections for Climate Impacts Research (CIL-GDPCR) collections contain bias corrected and downscaled 1/4° CMIP6 projections for temperature and precipitation.
See the project homepage for more information: github.com/ClimateImpactLab/downscaleCMIP6.
This tutorial covers accessing the STAC API to explore the collections and open a dataset. Additional tutorials are available at github.com/microsoft/PlanetaryComputerExamples.
import planetary_computer
import pystac_client
The CIL-GDPR datasets are grouped into two collections, depending on the license the data are provided under.
The data assets in this collection are a set of Zarr groups which can be opend by tools like xarray. Each Zarr group contains a single data variable (either pr
, tasmax
, or tasmin
). The Planetary Computer provides a single STAC item per experiment, and each STAC item has one asset per data variable.
To access the data, we'll create a pystac_client.Client
to access the Planetary Computer data catalog, including modifier=planetary_computer.sign_inplace
to automatically sign the returned results. See https://planetarycomputer.microsoft.com/docs/quickstarts/reading-stac/ for more.
catalog = pystac_client.Client.open(
"https://planetarycomputer.microsoft.com/api/stac/v1/",
modifier=planetary_computer.sign_inplace,
)
collection = catalog.get_collection("cil-gdpcir-cc-by")
item = collection.get_item("cil-gdpcir-NUIST-NESM3-ssp585-r1i1p1f1-day")
item.assets
{'pr': <Asset href=abfs://cil-gdpcir/ScenarioMIP/NUIST/NESM3/ssp585/r1i1p1f1/day/pr/v1.1.zarr>, 'tasmax': <Asset href=abfs://cil-gdpcir/ScenarioMIP/NUIST/NESM3/ssp585/r1i1p1f1/day/tasmax/v1.1.zarr>, 'tasmin': <Asset href=abfs://cil-gdpcir/ScenarioMIP/NUIST/NESM3/ssp585/r1i1p1f1/day/tasmin/v1.1.zarr>}
The STAC metadata includes all the required fields from the CMIP 6 controlled vocabularies.
item.properties["cmip6:source_id"]
'NESM3'
Use the Planetary Computer STAC API to find the exact data you want. You'll most likely want to query on the controlled vocabularies fields, under the cmip6:
prefix.. See the collection summary for the set of allowed values for each of those.
collection.summaries.to_dict()
{'cmip6:variable': ['pr', 'tasmax', 'tasmin'], 'cmip6:source_id': ['BCC-CSM2-MR', 'ACCESS-ESM1-5', 'ACCESS-CM2', 'MIROC-ES2L', 'MIROC6', 'NorESM2-LM', 'NorESM2-MM', 'GFDL-CM4', 'GFDL-ESM4', 'NESM3', 'MPI-ESM1-2-HR', 'HadGEM3-GC31-LL', 'UKESM1-0-LL', 'MPI-ESM1-2-LR', 'EC-Earth3', 'EC-Earth3-AerChem', 'EC-Earth3-CC', 'EC-Earth3-Veg', 'EC-Earth3-Veg-LR', 'CMCC-CM2-SR5', 'CMCC-ESM2'], 'cmip6:experiment_id': ['historical', 'ssp126', 'ssp245', 'ssp370', 'ssp585'], 'cmip6:institution_id': ['BCC', 'CAS', 'CCCma', 'CMCC', 'CSIRO', 'CSIRO-ARCCSS', 'DKRZ', 'EC-Earth-Consortium', 'INM', 'MIROC', 'MOHC', 'MPI-M', 'NCC', 'NOAA-GFDL', 'NUIST']}
search = catalog.search(
collections=["cil-gdpcir-cc-by"],
query={"cmip6:source_id": {"eq": "NESM3"}, "cmip6:experiment_id": {"eq": "ssp585"}},
)
items = search.get_all_items()
len(items)
/srv/conda/envs/notebook/lib/python3.10/site-packages/pystac_client/item_search.py:841: FutureWarning: get_all_items() is deprecated, use item_collection() instead. warnings.warn(
1
item = items[0]
item
id: cil-gdpcir-NUIST-NESM3-ssp585-r1i1p1f1-day |
bbox: [-180, -90, 180, 90] |
datetime: None |
cmip6:realm: atmos |
cmip6:source: NESM v3 (2016): aerosol: none atmos: ECHAM v6.3 (T63; 192 x 96 longitude/latitude; 47 levels; top level 1 Pa) atmosChem: none land: JSBACH v3.1 landIce: none ocean: NEMO v3.4 (NEMO v3.4, tripolar primarily 1deg; 384 x 362 longitude/latitude; 46 levels; top grid cell 0-6 m) ocnBgchem: none seaIce: CICE4.1 |
end_datetime: 2100-12-31T12:00:00Z |
cmip6:license: https://github.com/ClimateImpactLab/downscaleCMIP6/tree/master/data_licenses/NESM3.txt |
cmip6:mip_era: CMIP6 |
cmip6:product: model-output |
cmip6:table_id: day |
cube:variables: {'pr': {'type': 'data', 'unit': 'mm day-1', 'attrs': {'units': 'mm day-1'}, 'shape': [31390, 720, 1440], 'dimensions': ['time', 'lat', 'lon']}, 'tasmax': {'type': 'data', 'unit': 'K', 'attrs': {'units': 'K', 'comment': "maximum near-surface (usually, 2 meter) air temperature (add cell_method attribute 'time: max')", 'history': "2019-08-11T09:50:24Z altered by CMOR: Treated scalar dimension: 'height'. 2019-08-11T09:50:24Z altered by CMOR: Inverted axis: lat.", 'long_name': 'Daily Maximum Near-Surface Air Temperature', 'cell_methods': 'area: mean time: maximum', 'cell_measures': 'area: areacella', 'standard_name': 'air_temperature'}, 'shape': [31390, 720, 1440], 'dimensions': ['time', 'lat', 'lon'], 'description': 'Daily Maximum Near-Surface Air Temperature'}, 'tasmin': {'type': 'data', 'unit': 'K', 'attrs': {'units': 'K', 'comment': "minimum near-surface (usually, 2 meter) air temperature (add cell_method attribute 'time: min')", 'history': "2019-08-11T09:48:45Z altered by CMOR: Treated scalar dimension: 'height'. 2019-08-11T09:48:45Z altered by CMOR: Inverted axis: lat.", 'long_name': 'Daily Minimum Near-Surface Air Temperature', 'cell_methods': 'area: mean time: minimum', 'cell_measures': 'area: areacella', 'standard_name': 'air_temperature'}, 'shape': [31390, 720, 1440], 'dimensions': ['time', 'lat', 'lon'], 'description': 'Daily Minimum Near-Surface Air Temperature'}} |
start_datetime: 2015-01-01T12:00:00Z |
cmip6:frequency: day |
cmip6:source_id: NESM3 |
cube:dimensions: {'lat': {'axis': 'y', 'step': 0.25, 'type': 'spatial', 'extent': [-89.875, 89.875], 'reference_system': 'epsg:4326'}, 'lon': {'axis': 'x', 'step': 0.25, 'type': 'spatial', 'extent': [-179.875, 179.875], 'reference_system': 'epsg:4326'}, 'time': {'step': 'P1DT0H0M0S', 'type': 'temporal', 'extent': ['2015-01-01T12:00:00Z', '2100-12-31T12:00:00Z'], 'description': 'time'}} |
cmip6:experiment: update of RCP8.5 based on SSP5 |
cmip6:Conventions: CF-1.7 CMIP-6.2 |
cmip6:activity_id: ScenarioMIP |
cmip6:institution: Nanjing University of Information Science and Technology, Nanjing, 210044, China |
cmip6:source_type: AOGCM |
cmip6:experiment_id: ssp585 |
cmip6:forcing_index: 1 |
cmip6:physics_index: 1 |
cmip6:variant_label: r1i1p1f1 |
cmip6:institution_id: NUIST |
cmip6:sub_experiment: none |
cmip6:further_info_url: https://furtherinfo.es-doc.org/CMIP6.NUIST.NESM3.ssp585.none.r1i1p1f1 |
cmip6:realization_index: 1 |
cmip6:sub_experiment_id: none |
cmip6:data_specs_version: 01.00.30 |
cmip6:nominal_resolution: 250 km |
cmip6:initialization_index: 1 |
https://stac-extensions.github.io/datacube/v2.0.0/schema.json |
href: abfs://cil-gdpcir/ScenarioMIP/NUIST/NESM3/ssp585/r1i1p1f1/day/pr/v1.1.zarr |
type: application/vnd+zarr |
owner: cil-gdpcir-NUIST-NESM3-ssp585-r1i1p1f1-day |
cmip6:grid: T63 |
msft:https-url: https://rhgeuwest.blob.core.windows.net/cil-gdpcir/ScenarioMIP/NUIST/NESM3/ssp585/r1i1p1f1/day/pr/v1.1.zarr |
cmip6:grid_label: gn |
cmip6:tracking_id: hdl:21.14100/ed432434-922e-4cea-8400-c321598fd7cf hdl:21.14100/abea2bb8-09d0-4114-9051-fe232efe108e hdl:21.14100/205a607f-75f4-4919-b495-45fa8fdb77b8 |
cmip6:variable_id: pr |
xarray:open_kwargs: {'chunks': {}, 'engine': 'zarr', 'consolidated': True, 'storage_options': {'account_name': 'rhgeuwest', 'credential': 'st=2023-06-22T15%3A36%3A45Z&se=2023-06-30T15%3A36%3A45Z&sp=rl&sv=2021-06-08&sr=c&skoid=c85c15d6-d1ae-42d4-af60-e2ca0f81359b&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2023-06-23T15%3A36%3A44Z&ske=2023-06-30T15%3A36%3A44Z&sks=b&skv=2021-06-08&sig=C8zGe%2B5GRYp/uYA%2B4yhjz8Sk5ZztiuRwRmLEj5fMQM0%3D'}} |
cmip6:creation_date: 2019-08-11T09:53:50Z |
href: abfs://cil-gdpcir/ScenarioMIP/NUIST/NESM3/ssp585/r1i1p1f1/day/tasmax/v1.1.zarr |
type: application/vnd+zarr |
owner: cil-gdpcir-NUIST-NESM3-ssp585-r1i1p1f1-day |
cmip6:grid: T63 |
msft:https-url: https://rhgeuwest.blob.core.windows.net/cil-gdpcir/ScenarioMIP/NUIST/NESM3/ssp585/r1i1p1f1/day/tasmax/v1.1.zarr |
cmip6:grid_label: gn |
cmip6:tracking_id: hdl:21.14100/01f58d9c-1317-467e-813d-a2358cdf7954 hdl:21.14100/e027cda7-ac28-4e00-b03f-53ad2e6d30b4 hdl:21.14100/3898bc79-5174-4fcc-9637-4573914ad548 |
cmip6:variable_id: tasmax |
xarray:open_kwargs: {'chunks': {}, 'engine': 'zarr', 'consolidated': True, 'storage_options': {'account_name': 'rhgeuwest', 'credential': 'st=2023-06-22T15%3A36%3A45Z&se=2023-06-30T15%3A36%3A45Z&sp=rl&sv=2021-06-08&sr=c&skoid=c85c15d6-d1ae-42d4-af60-e2ca0f81359b&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2023-06-23T15%3A36%3A44Z&ske=2023-06-30T15%3A36%3A44Z&sks=b&skv=2021-06-08&sig=C8zGe%2B5GRYp/uYA%2B4yhjz8Sk5ZztiuRwRmLEj5fMQM0%3D'}} |
cmip6:creation_date: 2019-08-11T09:50:24Z |
href: abfs://cil-gdpcir/ScenarioMIP/NUIST/NESM3/ssp585/r1i1p1f1/day/tasmin/v1.1.zarr |
type: application/vnd+zarr |
owner: cil-gdpcir-NUIST-NESM3-ssp585-r1i1p1f1-day |
cmip6:grid: T63 |
msft:https-url: https://rhgeuwest.blob.core.windows.net/cil-gdpcir/ScenarioMIP/NUIST/NESM3/ssp585/r1i1p1f1/day/tasmin/v1.1.zarr |
cmip6:grid_label: gn |
cmip6:tracking_id: hdl:21.14100/1998e7f0-ad6a-4720-8150-9085db6f96b8 hdl:21.14100/ca181871-4103-481d-8764-b74c2448427f hdl:21.14100/fceb22c4-0454-4d68-bb48-1d903df19e63 |
cmip6:variable_id: tasmin |
xarray:open_kwargs: {'chunks': {}, 'engine': 'zarr', 'consolidated': True, 'storage_options': {'account_name': 'rhgeuwest', 'credential': 'st=2023-06-22T15%3A36%3A45Z&se=2023-06-30T15%3A36%3A45Z&sp=rl&sv=2021-06-08&sr=c&skoid=c85c15d6-d1ae-42d4-af60-e2ca0f81359b&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2023-06-23T15%3A36%3A44Z&ske=2023-06-30T15%3A36%3A44Z&sks=b&skv=2021-06-08&sig=C8zGe%2B5GRYp/uYA%2B4yhjz8Sk5ZztiuRwRmLEj5fMQM0%3D'}} |
cmip6:creation_date: 2019-08-11T09:48:45Z |
rel: collection |
href: https://planetarycomputer.microsoft.com/api/stac/v1/collections/cil-gdpcir-cc-by |
type: application/json |
rel: parent |
href: https://planetarycomputer.microsoft.com/api/stac/v1/collections/cil-gdpcir-cc-by |
type: application/json |
rel: root |
href: https://planetarycomputer.microsoft.com/api/stac/v1/ |
type: application/json |
title: Microsoft Planetary Computer STAC API |
rel: self |
href: https://planetarycomputer.microsoft.com/api/stac/v1/collections/cil-gdpcir-cc-by/items/cil-gdpcir-NUIST-NESM3-ssp585-r1i1p1f1-day |
type: application/geo+json |
We can now load the assets with xarray:
import xarray as xr
asset = item.assets["tasmax"]
ds = xr.open_dataset(asset.href, **asset.extra_fields["xarray:open_kwargs"])
ds
<xarray.Dataset> Dimensions: (lat: 720, lon: 1440, time: 31390) Coordinates: * lat (lat) float64 -89.88 -89.62 -89.38 -89.12 ... 89.38 89.62 89.88 * lon (lon) float64 -179.9 -179.6 -179.4 -179.1 ... 179.4 179.6 179.9 * time (time) object 2015-01-01 12:00:00 ... 2100-12-31 12:00:00 Data variables: tasmax (time, lat, lon) float32 dask.array<chunksize=(365, 360, 360), meta=np.ndarray> Attributes: (12/47) Conventions: CF-1.7 CMIP-6.2 activity_id: ScenarioMIP contact: climatesci@rhg.com creation_date: 2019-08-11T09:50:24Z data_specs_version: 01.00.30 dc6_bias_correction_method: Quantile Delta Method (QDM) ... ... sub_experiment_id: none table_id: day tracking_id: hdl:21.14100/01f58d9c-1317-467e-813d-a2358c... variable_id: tasmax variant_label: r1i1p1f1 version_id: v20190811
And form a datacube with xarray.combine_by_coords
.
import xarray as xr
asset = item.assets["tasmax"]
ds = xr.combine_by_coords(
[
xr.open_dataset(asset.href, **asset.extra_fields["xarray:open_kwargs"])
for asset in item.assets.values()
],
combine_attrs="drop_conflicts",
)
ds
<xarray.Dataset> Dimensions: (lat: 720, lon: 1440, time: 31390) Coordinates: * lat (lat) float64 -89.88 -89.62 -89.38 -89.12 ... 89.38 89.62 89.88 * lon (lon) float64 -179.9 -179.6 -179.4 -179.1 ... 179.4 179.6 179.9 * time (time) object 2015-01-01 12:00:00 ... 2100-12-31 12:00:00 Data variables: pr (time, lat, lon) float64 dask.array<chunksize=(365, 360, 360), meta=np.ndarray> tasmax (time, lat, lon) float32 dask.array<chunksize=(365, 360, 360), meta=np.ndarray> tasmin (time, lat, lon) float32 dask.array<chunksize=(365, 360, 360), meta=np.ndarray> Attributes: (12/40) Conventions: CF-1.7 CMIP-6.2 activity_id: ScenarioMIP contact: climatesci@rhg.com data_specs_version: 01.00.30 dc6_bias_correction_method: Quantile Delta Method (QDM) dc6_citation: Please refer to https://github.com/ClimateI... ... ... source_type: AOGCM sub_experiment: none sub_experiment_id: none table_id: day variant_label: r1i1p1f1 version_id: v20190811
We'll load the data for a specific date and plot the result.
tmax = ds.tasmax.isel(time=0).load()
tmax.plot(size=10);