{ "cells": [ { "cell_type": "markdown", "id": "0", "metadata": {}, "source": [ "# Regridding climate data with xESMF\n", "\n", "A common element of climate data workflows is regridding, or reprojection, of model data unto more standard grids, or simply unto another dataset's grid. The powerful [ESMF](http://earthsystemmodeling.org/docs/release/ESMF_8_0_1/ESMF_usrdoc/) program, written in FORTRAN, has long been a reference in the matter. The [xESMF](https://pangeo-xesmf.readthedocs.io/en/latest/) python package provides an easy to use high-level API for using ESMF's methods. This notebook shows some examples of common regridding operations.\n", "\n", "Regridding with `xESMF` is usually a two step process: \n", "\n", " 1. Create a `Regridder` objects from two datasets, defining the input and the output grids. This compute a weights mask which can, if needed, be saved to a netCDCF file.\n", " 2. Regrid a DataArray or Dataset by calling the `Regridder` with it. As the weights have already been computed, it reuses them for all time slices, which allows much better performance than, for example, interpolation using `scipy.interpolation.interpn`." ] }, { "cell_type": "code", "execution_count": 1, "id": "1", "metadata": {}, "outputs": [], "source": [ "# NBVAL_IGNORE_OUTPUT\n", "import geopandas as gpd # isort: skip\n", "from owslib.wfs import WebFeatureService # isort: skip\n", "\n", "import warnings\n", "\n", "# ipykernel_launcher.py:1: DeprecationWarning: xclim.subset is deprecated in xclim v0.19.1-beta. Please take note that xclim presently exposes the 'clisops' library subsetting API via `from clisops.core import subset`.\n", "warnings.filterwarnings(\"ignore\", category=DeprecationWarning)\n", "\n", "# Other utilities for style and clean examples\n", "import copy\n", "import json\n", "\n", "import cf_xarray as cfxr\n", "import matplotlib.pyplot as plt\n", "import shapely\n", "import xarray as xr\n", "import xesmf as xe\n", "from clisops.core.subset import subset_bbox # For subsetting\n", "from xclim.testing import open_dataset # For opening xclim's test data\n", "\n", "# A colormap with grey where the data is missing\n", "cmap = copy.copy(plt.cm.get_cmap(\"viridis\"))\n", "cmap.set_bad(\"lightgray\")" ] }, { "cell_type": "markdown", "id": "2", "metadata": {}, "source": [ "## Simple example : Bilinear regridding from model to obs\n", "\n", "Our input in this example is a year of monthly sea ice concentration data from a CanESM5 run for CMIP6. It lies on an irregular grid defined by `latitude` and `longitude` coordinates. We'll interpolate the sea ice concentration to a regular observational grid from Natural Resources Canada. \n", "\n", "### The input data" ] }, { "cell_type": "code", "execution_count": 2, "id": "3", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
<xarray.Dataset>\n", "Dimensions: (time: 12, bnds: 2, j: 291, i: 360, vertices: 4)\n", "Coordinates:\n", " * time (time) object 2020-01-16 12:00:00 ... 2020-12-16 12:0...\n", " * j (j) int32 0 1 2 3 4 5 6 ... 284 285 286 287 288 289 290\n", " * i (i) int32 0 1 2 3 4 5 6 ... 353 354 355 356 357 358 359\n", " type |S64 b'sea_ice'\n", " latitude (j, i) float64 ...\n", " longitude (j, i) float64 ...\n", "Dimensions without coordinates: bnds, vertices\n", "Data variables:\n", " time_bnds (time, bnds) object 2020-01-01 00:00:00 ... 2021-01-0...\n", " vertices_latitude (j, i, vertices) float64 ...\n", " vertices_longitude (j, i, vertices) float64 ...\n", " siconc (time, j, i) float32 ...\n", " areacello (j, i) float32 ...\n", "Attributes: (12/56)\n", " CCCma_model_hash: fc4bb7db954c862d023b546e19aec6c588bc0552\n", " CCCma_parent_runid: p2-his13\n", " CCCma_pycmor_hash: 26c970628162d607fffd14254956ebc6dd3b6f49\n", " CCCma_runid: p2-s4513\n", " Conventions: CF-1.7 CMIP-6.2\n", " YMDH_branch_time_in_child: 2015:01:01:00\n", " ... ...\n", " license: CMIP6 model data produced by The Governm...\n", " cmor_version: 3.5.0\n", " tracking_id: hdl:21.14100/9e4f804b-c161-44fa-acd1-c2e...\n", " DODS.strlen: 64\n", " DODS.dimName: maxStrlen64\n", " DODS_EXTRA.Unlimited_Dimension: time
<xarray.Dataset>\n", "Dimensions: (lat: 207, lon: 570)\n", "Coordinates:\n", " * lat (lat) float32 67.54 67.46 67.38 67.29 ... 50.62 50.54 50.46 50.38\n", " * lon (lon) float32 -99.46 -99.38 -99.29 -99.21 ... -52.21 -52.13 -52.04\n", "Data variables:\n", " tasmin (lat, lon) float32 ...\n", " tasmax (lat, lon) float32 ...\n", " pr (lat, lon) float32 ...\n", "Attributes: (12/15)\n", " Conventions: CF-1.5\n", " title: NRCAN ANUSPLIN daily gridded dataset : version 2\n", " history: Fri Jan 25 14:11:15 2019 : Convert from original fo...\n", " institute_id: NRCAN\n", " frequency: day\n", " abstract: Gridded daily observational dataset produced by Nat...\n", " ... ...\n", " dataset_id: NRCAN_anusplin_daily_v2\n", " version: 2.0\n", " license_type: permissive\n", " license: https://open.canada.ca/en/open-government-licence-c...\n", " attribution: The authors provide this data under the Environment...\n", " citation: Natural Resources Canada ANUSPLIN interpolated hist...
<xarray.Dataset>\n", "Dimensions: (time: 1, bounds: 2, lat: 64, lon: 128)\n", "Coordinates:\n", " * lat (lat) float64 -87.86 -85.1 -82.31 -79.53 ... 82.31 85.1 87.86\n", " * lon (lon) float64 0.0 2.812 5.625 8.438 ... 348.8 351.6 354.4 357.2\n", " height float64 2.0\n", "Dimensions without coordinates: time, bounds\n", "Data variables:\n", " time_bnds (time, bounds) object 1993-05-20 00:00:00 1993-05-21 00:00:00\n", " lat_bnds (lat, bounds) float64 -90.0 -86.48 -86.48 ... 86.48 86.48 90.0\n", " lon_bnds (lon, bounds) float64 -1.406 1.406 1.406 ... 355.8 355.8 358.6\n", " tasmin (time, lat, lon) float32 208.3 207.9 207.4 206.8 ... nan nan nan\n", "Attributes: (12/32)\n", " institution: CCCma (Canadian Centre for Climate Model...\n", " institute_id: CCCma\n", " experiment_id: historical\n", " source: CanESM2 2010 atmosphere: CanAM4 (AGCM15i...\n", " model_id: CanESM2\n", " forcing: GHG,Oz,SA,BC,OC,LU,Sl,Vl (GHG includes C...\n", " ... ...\n", " title: CanESM2 model output prepared for CMIP5 ...\n", " parent_experiment: pre-industrial control\n", " modeling_realm: atmos\n", " realization: 1\n", " cmor_version: 2.5.4\n", " DODS_EXTRA.Unlimited_Dimension: time
<xarray.Dataset>\n", "Dimensions: (lat: 510, lon: 1068)\n", "Coordinates:\n", " * lat (lat) float32 83.46 83.38 83.29 83.21 ... 41.29 41.21 41.12 41.04\n", " * lon (lon) float32 -141.0 -140.9 -140.8 -140.7 ... -52.21 -52.13 -52.04\n", "Data variables:\n", " tasmin (lat, lon) float32 ...\n", "Attributes: (12/15)\n", " Conventions: CF-1.5\n", " title: NRCAN ANUSPLIN daily gridded dataset : version 2\n", " history: Fri Jan 25 14:11:15 2019 : Convert from original fo...\n", " institute_id: NRCAN\n", " frequency: day\n", " abstract: Gridded daily observational dataset produced by Nat...\n", " ... ...\n", " dataset_id: NRCAN_anusplin_daily_v2\n", " version: 2.0\n", " license_type: permissive\n", " license: https://open.canada.ca/en/open-government-licence-c...\n", " attribution: The authors provide this data under the Environment...\n", " citation: Natural Resources Canada ANUSPLIN interpolated hist...
<xarray.DataArray (geom: 10)>\n", "array([ nan, nan, 274.64337, 275.4841 , nan, 276.23578,\n", " 274.05746, 276.86087, 275.4918 , 276.8586 ], dtype=float32)\n", "Coordinates:\n", " lon (geom) float64 -66.01 -63.91 -77.09 -76.16 ... -73.26 -76.76 -73.98\n", " lat (geom) float64 49.21 48.29 46.43 46.91 ... 47.13 48.81 48.15 48.04\n", "Dimensions without coordinates: geom\n", "Attributes:\n", " regrid_method: conservative
<xarray.DataArray (geom: 10)>\n", "array([ nan, nan, 274.64337, 275.4841 , nan, 276.23578,\n", " 274.05746, 276.86087, 275.4918 , 276.8586 ], dtype=float32)\n", "Coordinates:\n", " lon (geom) float64 -66.01 -63.91 -77.09 -76.16 ... -73.26 -76.76 -73.98\n", " lat (geom) float64 49.21 48.29 46.43 46.91 ... 47.13 48.81 48.15 48.04\n", " * geom (geom) object 'La Haute-Gaspésie' 'Le Rocher-Percé' ... 'La Tuque'\n", " AREA (geom) float64 1.415 1.543 1.654 1.673 ... 2.283 2.364 3.307 3.573\n", "Attributes:\n", " regrid_method: conservative
\n", " | geometry | \n", "AREA | \n", "tasmin | \n", "
---|---|---|---|
MRS_NM_MRC | \n", "\n", " | \n", " | \n", " |
La Haute-Gaspésie | \n", "POLYGON ((-65.19300 49.18900, -65.18720 49.099... | \n", "1.414604 | \n", "NaN | \n", "
Le Rocher-Percé | \n", "POLYGON ((-62.99910 48.62500, -62.99910 47.157... | \n", "1.542547 | \n", "NaN | \n", "
Pontiac | \n", "POLYGON ((-77.91790 47.26940, -77.64730 47.269... | \n", "1.653789 | \n", "274.643372 | \n", "
La Vallée-de-la-Gatineau | \n", "POLYGON ((-76.27030 47.68990, -76.27000 47.692... | \n", "1.672640 | \n", "275.484100 | \n", "
La Haute-Côte-Nord | \n", "POLYGON ((-69.50820 49.99830, -69.51050 49.997... | \n", "1.800530 | \n", "NaN | \n", "
Antoine-Labelle | \n", "POLYGON ((-75.04050 47.76270, -74.88940 47.762... | \n", "1.923892 | \n", "276.235779 | \n", "
Témiscamingue | \n", "MULTIPOLYGON (((-77.57920 47.44240, -77.58630 ... | \n", "2.282582 | \n", "274.057465 | \n", "
Le Domaine-du-Roy | \n", "POLYGON ((-73.68260 49.99730, -73.68440 49.997... | \n", "2.363714 | \n", "276.860870 | \n", "
La Vallée-de-l'Or | \n", "MULTIPOLYGON (((-77.57920 47.44240, -77.57290 ... | \n", "3.306656 | \n", "275.491791 | \n", "
La Tuque | \n", "POLYGON ((-74.67630 48.99960, -74.62850 48.967... | \n", "3.572838 | \n", "276.858612 | \n", "