Working with REMO domains
The domain module should give some tools to work with preconfigured or user defined domains. Domains are defined as xarray datasets that will contain dimensions and coodinates according to CF-conventions. The pyremo domain module actually uses the py-cordex domains module in the background just with another set of tables.
NOTE: Please be aware that a remo domain is usually a little larger than the “official” cordex domain according to the archive specification since the regional model usually accounts for a “buffer” zone where the lateral boundary conditions are nudged.
Working with domain information
[1]:
import pyremo as pr
The domain module contains some useful functions to work with cordex meta data, e.g., you can get some domain grid information using
[2]:
pr.domain_info("EUR-11")
Downloading file 'domains.csv' from 'https://raw.githubusercontent.com/remo-rcm/tables/main/domains/domains.csv' to '/home/docs/.pyremo'.
[2]:
{'domain_id': 'EUR-11',
'region': 4,
'domain': 'Europe high-res.',
'nlon': 433,
'nlat': 433,
'll_lon': -28.925,
'll_lat': -23.925,
'dlon': 0.11,
'dlat': 0.11,
'pollon': -162.0,
'pollat': 39.25,
'ur_lon': None,
'ur_lat': None}
All available cordex domains are in this table:
[3]:
pr.domains.table
[3]:
region | domain | nlon | nlat | ll_lon | ll_lat | dlon | dlat | pollon | pollat | ur_lon | ur_lat | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
domain_id | ||||||||||||
AFR-11 | 5 | Africa | 801 | 865 | -26.23500 | -49.33500 | 0.1100 | 0.1100 | 180.00 | 90.00 | NaN | NaN |
AFR-22 | 5 | Africa | 401 | 433 | -26.29000 | -49.39000 | 0.2200 | 0.2200 | 180.00 | 90.00 | NaN | NaN |
AFR-44 | 5 | Africa | 217 | 217 | -29.92000 | -49.28000 | 0.4400 | 0.4400 | 180.00 | 90.00 | NaN | NaN |
AUS-11 | 9 | Australasia | 811 | 541 | 321.49000 | -60.20000 | 0.1100 | 0.1100 | 141.38 | 60.31 | NaN | NaN |
AUS-22 | 9 | Australasia | 433 | 271 | 138.31000 | -24.53000 | 0.2200 | 0.2200 | 141.38 | 60.31 | NaN | NaN |
AUS-44 | 9 | Australasia | 217 | 145 | 321.82000 | -59.87000 | 0.4400 | 0.4400 | 141.38 | 60.31 | NaN | NaN |
CAM-11 | 2 | Central America | 865 | 481 | 294.09000 | -75.63000 | 0.1100 | 0.1100 | 113.98 | 75.74 | NaN | NaN |
CAM-22 | 2 | Central America | 433 | 241 | -54.45000 | -30.47000 | 0.2200 | 0.2200 | 113.98 | 75.74 | NaN | NaN |
CAM-44 | 2 | Central America | 241 | 129 | -59.84000 | -32.12000 | 0.4400 | 0.4400 | 113.98 | 75.74 | NaN | NaN |
CAS-11 | 8 | Central Asia | 641 | 433 | -36.02500 | -22.60500 | 0.1100 | 0.1100 | -103.39 | 43.48 | NaN | NaN |
CAS-22 | 8 | Central Asia | 325 | 217 | -36.63000 | -22.77000 | 0.2200 | 0.2200 | -103.39 | 43.48 | NaN | NaN |
CAS-44 | 8 | Central Asia | 181 | 121 | -40.48000 | -25.52000 | 0.4400 | 0.4400 | -103.39 | 43.48 | NaN | NaN |
EAS-11 | 7 | East Asia | 811 | 513 | 116.41000 | -60.89000 | 0.1100 | 0.1100 | -63.70 | 61.00 | NaN | NaN |
EAS-22 | 7 | East Asia | 433 | 271 | -47.41000 | -24.30000 | 0.2200 | 0.2200 | 296.30 | 61.00 | NaN | NaN |
EAS-44 | 7 | East Asia | 201 | 163 | 476.74000 | -60.56000 | 0.4400 | 0.4400 | 296.30 | 61.00 | NaN | NaN |
EUR-11 | 4 | Europe high-res. | 433 | 433 | -28.92500 | -23.92500 | 0.1100 | 0.1100 | -162.00 | 39.25 | NaN | NaN |
EUR-22 | 4 | Europe | 241 | 217 | -31.62000 | -24.64000 | 0.2200 | 0.2200 | -162.00 | 39.25 | NaN | NaN |
EUR-44 | 4 | Europe | 129 | 121 | -31.73000 | -26.73000 | 0.4400 | 0.4400 | -162.00 | 39.25 | NaN | NaN |
NAM-11 | 3 | North America | 641 | 541 | 263.11000 | -42.39000 | 0.1100 | 0.1100 | 83.00 | 42.50 | NaN | NaN |
NAM-22 | 3 | North America | 321 | 271 | -35.31000 | -29.83000 | 0.2200 | 0.2200 | 83.00 | 42.50 | NaN | NaN |
NAM-44 | 3 | North America | 181 | 151 | -39.60000 | -33.24000 | 0.4400 | 0.4400 | 83.00 | 42.50 | NaN | NaN |
SAM-11 | 1 | South America | 601 | 721 | 124.05000 | -70.49000 | 0.1100 | 0.1100 | -56.06 | 70.60 | NaN | NaN |
SAM-22 | 1 | South America | 301 | 361 | 142.71000 | -41.47000 | 0.2200 | 0.2200 | -56.06 | 70.60 | NaN | NaN |
SAM-44 | 1 | South America | 161 | 181 | 140.40000 | -41.36000 | 0.4400 | 0.4400 | -56.06 | 70.60 | NaN | NaN |
SEA-22 | 14 | South East Asia | 289 | 217 | 86.40000 | -17.82000 | 0.2200 | 0.2200 | 180.00 | 90.00 | NaN | NaN |
WAS-22 | 6 | South Asia | 401 | 271 | -33.99000 | -22.99000 | 0.2200 | 0.2200 | -123.34 | 79.95 | NaN | NaN |
EUR+NA-11 | 4 | Europe + North Atlantic | 649 | 433 | 18.11000 | -39.14000 | 0.1100 | 0.1100 | -162.00 | 39.25 | NaN | NaN |
HUN-11 | 4 | Hungary | 301 | 145 | 360.11000 | -89.89000 | 0.1100 | 0.1100 | 180.00 | 90.00 | NaN | NaN |
SASSCAL-22 | 5 | Southern Africa | 433 | 433 | 360.22000 | -89.78000 | 0.2200 | 0.2200 | 180.00 | 90.00 | NaN | NaN |
GAR-11 | 4 | Greater Alpine Region | 145 | 129 | -14.95500 | -12.15500 | 0.1100 | 0.1100 | -162.00 | 39.25 | NaN | NaN |
EUN-0275 | 4 | EUCP Northern Europe | 649 | 811 | -9.99125 | -0.20625 | 0.0275 | 0.0275 | -162.00 | 39.25 | NaN | NaN |
EUC-0275 | 4 | EUCP Central Europe | 361 | 401 | -9.52375 | -5.29375 | 0.0275 | 0.0275 | -162.00 | 39.25 | NaN | NaN |
SGAR-0275 | 4 | Greater Alpine Region | 289 | 271 | -9.38625 | -9.66625 | 0.0275 | 0.0275 | -162.00 | 39.25 | NaN | NaN |
GAR-0275 | 4 | Greater Alpine Region | 501 | 481 | -13.92375 | -11.67375 | 0.0275 | 0.0275 | -162.00 | 39.25 | -0.17375 | 1.52625 |
MEU-11 | 4 | Mid-Europe | 121 | 121 | -10.89000 | -6.89000 | 0.1100 | 0.1100 | -162.00 | 39.25 | NaN | NaN |
WAF-11 | 5 | Westafrica | 361 | 271 | -20.68000 | 2.64000 | 0.1100 | 0.1100 | 180.00 | 90.00 | NaN | NaN |
MSEA-11 | 14 | South East Asia Mainland | 145 | 181 | 92.34000 | 7.12000 | 0.1100 | 0.1100 | 180.00 | 80.00 | NaN | NaN |
MOMED-11 | 12 | Mediterranean | 487 | 321 | -27.92500 | -25.92500 | 0.1100 | 0.1100 | 198.00 | 39.25 | NaN | NaN |
HYDRASIA-11 | 8 | Central Asia | 257 | 271 | -20.02500 | -20.60500 | 0.1100 | 0.1100 | -103.39 | 43.48 | NaN | NaN |
GUI-0275 | 5 | Guinea | 811 | 321 | -17.03625 | 4.08375 | 0.0275 | 0.0275 | 180.00 | 90.00 | 5.23875 | 12.88375 |
ALPX-3 | 4 | Extended Alpine Region | 721 | 577 | -18.62625 | -11.20625 | 0.0275 | 0.0275 | -162.00 | 39.25 | NaN | NaN |
NSEA-3 | 4 | North Sea | 649 | 541 | -15.98625 | -0.97625 | 0.0275 | 0.0275 | -162.00 | 39.25 | NaN | NaN |
EUR-11
example
The heart of the module are some functions that create a dataset from the grid information, e.g.
[4]:
eur11 = pr.remo_domain("EUR-11", dummy="topo")
eur11
/home/docs/checkouts/readthedocs.org/user_builds/pyremo/conda/latest/lib/python3.10/site-packages/cf_xarray/accessor.py:671: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.
unused_keys = set(attribute.keys()) - set(inverted)
/home/docs/checkouts/readthedocs.org/user_builds/pyremo/conda/latest/lib/python3.10/site-packages/cf_xarray/accessor.py:672: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.
for key, value in attribute.items():
[4]:
<xarray.Dataset> Size: 4MB Dimensions: (rlon: 433, rlat: 433) Coordinates: * rlon (rlon) float64 3kB -28.93 -28.82 ... 18.48 18.59 * rlat (rlat) float64 3kB -23.93 -23.82 ... 23.48 23.59 lon (rlat, rlon) float64 1MB -10.32 -10.23 ... 68.65 lat (rlat, rlon) float64 1MB 21.28 21.32 ... 67.8 Data variables: rotated_latitude_longitude int32 4B 0 topo (rlat, rlon) float32 750kB 283.0 283.0 ... 44.67 Attributes: CORDEX_domain: EUR-11
The dummy='topo'
argument means, we want a dummy variable in the dataset to see how the domain looks like. For the dummy topography, we use the cdo topo
operator in the background. So maybe you have to install python-cdo
, e.g., conda install -c conda-forge python-cdo
. Working with xarray datasets means, that we can use all the nice functions of xarray including plotting, e.g.,
[5]:
eur11.topo.plot(cmap="terrain")
Matplotlib is building the font cache; this may take a moment.
[5]:
<matplotlib.collections.QuadMesh at 0x7fa9e89c6fb0>
[6]:
eur11.topo.plot(x="lon", y="lat", cmap="terrain")
[6]:
<matplotlib.collections.QuadMesh at 0x7fa9e8885780>
Let’s define a slightly more sophisticated plotting function that uses cartopy for the right projection with a rotated pole:
[7]:
def plot(da, pole, vmin=None, vmax=None, borders=True, title=""):
"""plot a domain using the right projection with cartopy"""
%matplotlib inline
import cartopy.crs as ccrs
import cartopy.feature as cf
import matplotlib.pyplot as plt
plt.figure(figsize=(20, 10))
projection = ccrs.PlateCarree()
transform = ccrs.RotatedPole(pole_latitude=pole[1], pole_longitude=pole[0])
# ax = plt.axes(projection=projection)
ax = plt.axes(projection=transform)
# ax.set_extent([ds_sub.rlon.min(), ds_sub.rlon.max(), ds_sub.rlat.min(), ds_sub.rlat.max()], crs=transform)
ax.gridlines(
draw_labels=True,
linewidth=0.5,
color="gray",
xlocs=range(-180, 180, 10),
ylocs=range(-90, 90, 5),
)
da.plot(
ax=ax,
cmap="terrain",
transform=transform,
vmin=vmin,
vmax=vmax,
x="rlon",
y="rlat",
)
ax.coastlines(resolution="50m", color="black", linewidth=1)
if borders:
ax.add_feature(cf.BORDERS)
ax.set_title("")
[8]:
pole_eur = (
eur11.rotated_latitude_longitude.grid_north_pole_longitude,
eur11.rotated_latitude_longitude.grid_north_pole_latitude,
)
pole_eur
[8]:
(-162.0, 39.25)
[9]:
plot(eur11.topo, pole_eur)
/home/docs/checkouts/readthedocs.org/user_builds/pyremo/conda/latest/lib/python3.10/site-packages/cartopy/io/__init__.py:241: DownloadWarning: Downloading: https://naturalearth.s3.amazonaws.com/50m_physical/ne_50m_coastline.zip
warnings.warn(f'Downloading: {url}', DownloadWarning)
/home/docs/checkouts/readthedocs.org/user_builds/pyremo/conda/latest/lib/python3.10/site-packages/cartopy/io/__init__.py:241: DownloadWarning: Downloading: https://naturalearth.s3.amazonaws.com/110m_cultural/ne_110m_admin_0_boundary_lines_land.zip
warnings.warn(f'Downloading: {url}', DownloadWarning)
User defined domain
The domains are created using the create_dataset
function from the `py-cordex
<https://py-cordex.readthedocs.io>`__ package, e.g.:
[10]:
from cordex import create_dataset
Let’s create the EUR-11 domain manually from the numbers in the table:
[11]:
eur11_user = create_dataset(
nlon=433,
nlat=433,
dlon=0.11,
dlat=0.11,
ll_lon=-28.925,
ll_lat=-23.925,
pollon=-162.00,
pollat=39.25,
dummy="topo",
)
/home/docs/checkouts/readthedocs.org/user_builds/pyremo/conda/latest/lib/python3.10/site-packages/cf_xarray/accessor.py:671: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.
unused_keys = set(attribute.keys()) - set(inverted)
/home/docs/checkouts/readthedocs.org/user_builds/pyremo/conda/latest/lib/python3.10/site-packages/cf_xarray/accessor.py:672: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.
for key, value in attribute.items():
We can check that this gives the same result as our preconfigured domain.
[12]:
eur11_user.equals(eur11)
[12]:
True
You can now use the create_dataset
function to create any domain as an xarray dataset.
[13]:
afr11 = pr.remo_domain("AFR-11", dummy="topo")
afr11
/home/docs/checkouts/readthedocs.org/user_builds/pyremo/conda/latest/lib/python3.10/site-packages/cf_xarray/accessor.py:671: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.
unused_keys = set(attribute.keys()) - set(inverted)
/home/docs/checkouts/readthedocs.org/user_builds/pyremo/conda/latest/lib/python3.10/site-packages/cf_xarray/accessor.py:672: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.
for key, value in attribute.items():
[13]:
<xarray.Dataset> Size: 14MB Dimensions: (rlon: 801, rlat: 865) Coordinates: * rlon (rlon) float64 6kB -26.23 -26.12 ... 61.66 61.77 * rlat (rlat) float64 7kB -49.34 -49.23 ... 45.6 45.71 lon (rlat, rlon) float64 6MB -26.23 -26.13 ... 61.77 lat (rlat, rlon) float64 6MB -49.34 -49.34 ... 45.71 Data variables: rotated_latitude_longitude int32 4B 0 topo (rlat, rlon) float32 3MB -4.646e+03 ... 56.0 Attributes: CORDEX_domain: AFR-11
[14]:
pole_afr = (
afr11.rotated_latitude_longitude.grid_north_pole_longitude,
afr11.rotated_latitude_longitude.grid_north_pole_latitude,
)
pole_afr
[14]:
(180.0, 90.0)
[15]:
plot(afr11.topo, pole_afr)
Cropping the REMO domain
Sometimes it might be neccessary to crop the REMO data to the official CORDEX grid size, e.g., for cmorization. This can now easily be done like this:
[16]:
import numpy as np
from cordex import cordex_domain
eur11_cordex = cordex_domain("EUR-11", dummy="topo")
Downloading file 'rotated-latitude-longitude.csv' from 'https://raw.githubusercontent.com/WCRP-CORDEX/domain-tables/main/rotated-latitude-longitude.csv' to '/home/docs/.py-cordex'.
/home/docs/checkouts/readthedocs.org/user_builds/pyremo/conda/latest/lib/python3.10/site-packages/cf_xarray/accessor.py:671: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.
unused_keys = set(attribute.keys()) - set(inverted)
/home/docs/checkouts/readthedocs.org/user_builds/pyremo/conda/latest/lib/python3.10/site-packages/cf_xarray/accessor.py:672: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.
for key, value in attribute.items():
[17]:
# crop = eur11.sel(rlon=slice(eur11_cordex.rlon.min(), eur11_cordex.rlon.max()), rlat=slice(eur11_cordex.rlat.min(), eur11_cordex.rlat.max()))
crop = eur11.sel(rlon=eur11_cordex.rlon, rlat=eur11_cordex.rlat, method="nearest")
[18]:
plot(crop.topo, pole_eur)
[19]:
crop
[19]:
<xarray.Dataset> Size: 4MB Dimensions: (rlon: 424, rlat: 412) Coordinates: * rlon (rlon) float64 3kB -28.38 -28.27 ... 18.05 18.16 * rlat (rlat) float64 3kB -23.38 -23.27 ... 21.73 21.84 lon (rlat, rlon) float64 1MB -10.06 -9.964 ... 64.96 lat (rlat, rlon) float64 1MB 21.99 22.03 ... 66.69 Data variables: rotated_latitude_longitude int32 4B 0 topo (rlat, rlon) float32 699kB 284.0 246.0 ... 509.0 Attributes: CORDEX_domain: EUR-11