{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Plot ESM data on *unstructured* grids with `psyplot`\n", "\n", "This notebook introduces you to the `mapplot` function of the package `psyplot` and its plugin `psy_maps`.\n", "It is suitable to plot maps from data on unstructured grids like the ones from ICON and FESOM.\n", "\n", "We therefore search for the corresponding data in the CMIP6 data pool with intake-esm.\n", "Afterwards, we open a file with `xarray` and configure the opened xarray dataset as well as psyplot for a map plot.\n", "\n", "This Jupyter notebook is meant to run in the [Jupyterhub](https://jupyterhub.dkrz.de/hub/login?next=%2Fhub%2Fhome) server of the German Climate Computing Center [DKRZ](https://www.dkrz.de/). The DKRZ hosts the CMIP data pool including 4 petabytes of CMIP6 data. Please, choose the Python 3 unstable kernel on the Kernel tab above, it contains all the common geoscience packages. See more information on how to run Jupyter notebooks at DKRZ [here](https://www.dkrz.de/up/systems/mistral/programming/jupyter-notebook).\n", "\n", "Running this Jupyter notebook in your premise, which is also known as [client-side](https://en.wikipedia.org/wiki/Client-side) computing, will require that you install the necessary packages\n", "`intake`, `xarray`, `maplotlib`, `psyplot`, `psy_maps`\n", "\n", "and either download the data or use the `opendap_url` column of the intake catalog if available." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Learning Objectives\n", "\n", "- How to access data on an *unstructured* grid from the DKRZ CMIP data pool with `intake-esm`\n", "- How to subset data with `xarray`\n", "- How to visualize the results with `matplotlib`, `psyplot` and `psy_maps`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import psyplot.project as psy\n", "import matplotlib as mpl\n", "import xarray as xr\n", "import intake" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We open a swift catalog from dkrz cloud which is accessible without authentication." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Path to master catalog on the DKRZ server\n", "#dkrz_catalog=intake.open_catalog([\"https://dkrz.de/s/intake\"])\n", "#\n", "#only for the web page we need to take the original link:\n", "parent_col=intake.open_catalog([\"https://gitlab.dkrz.de/data-infrastructure-services/intake-esm/-/raw/master/esm-collections/cloud-access/dkrz_catalog.yaml\"])\n", "list(parent_col)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "col=parent_col[\"dkrz_cmip6_disk\"]\n", "col.df[\"uri\"]=col.df[\"uri\"].str.replace(\"lustre/\",\"lustre02/\") \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this example, we aim at plotting the **Sea Surface Temperature** `tos` of the upper boundary of the liquid ocean, including temperatures below sea-ice and floating ice shelves from the earth system model **AWI-CM-1-1-MR**.\n", "We therefore search for `tos` in the catalog for monthly frequency. We only use one realization `r1i1p1f1` of one experiment only." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "tos=col.search(source_id=\"AWI-CM-1-1-MR\",\n", " experiment_id=\"ssp370\",\n", " variable_id=\"tos\",\n", " table_id=\"Omon\",\n", " member_id=\"r1i1p1f1\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "tos.df[\"uri\"].to_list()[0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We now open the file on the mistral lustre file system. Note that if you work remotely, you could try to use `opendap_url` instead of `path`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "dset = xr.open_dataset(tos.df[\"uri\"].to_list()[0],\n", " decode_cf=True,\n", " chunks={\"time\":1},\n", " lock=False)\n", "dset" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In order to make `tos` plottable, we set the following configuration.\n", "- The `CDI_grid_type` is a keyword for `psyplot`. It must match the *grid type* of the source model.\n", "- Coordinates are not fully recognized by `xarray` so that we have to add some manually (version from Dec 2020)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "dset[\"tos\"][\"CDI_grid_type\"]=\"unstructured\"\n", "coordlist=[\"vertices_latitude\", \"vertices_longitude\", \"lat_bnds\", \"lon_bnds\"]\n", "dset=dset.set_coords([coord for coord in dset.data_vars if coord in coordlist])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The following is based on the [psyplot example](https://psyplot.readthedocs.io/projects/psy-maps/en/latest/examples/example_ugrid.html#gallery-examples-example-ugrid-ipynb). We set a resoltion for the land sea mask `lsm` and a color map via `cmap`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "psy.rcParams['plotter.maps.xgrid'] = False\n", "psy.rcParams['plotter.maps.ygrid'] = False\n", "mpl.rcParams['figure.figsize'] = [10, 8.]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def plot_unstructured():\n", " iconplot11=psy.plot.mapplot(\n", " dset, name=\"tos\", cmap='rainbow',\n", " clabel=dset[\"tos\"].description,\n", " stock_img=True, lsm='50m')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We now do the same with a smaller subset to highlight the fine resolution and the structure of the AWI ocean model FESOM.\n", "We first *subset* the data because otherwise plotting takes too long. We choose indices of dimensions with the `xarray` function `isel`. We select a slice of two time steps and focus on a region Ireland. We have to save the data to an intermediate file `test.nc` because otherwise we receive an error." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "dset[\"lat\"]=dset.lat.load()\n", "dset[\"lon\"]=dset.lon.load()\n", "dset2 = dset.isel(time=slice(1,2)).where( (dset.lon > -10. ) &\n", " (dset.lon < 50. ) &\n", " (dset.lat > 40. ) &\n", " (dset.lat < 70. ), drop=True).drop(\"time_bnds\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "dset2" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "dset2.to_netcdf(\"test.nc\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "dset2.close()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "dset=xr.open_dataset(\"test.nc\",\n", " decode_cf=True)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "dset[\"tos\"][\"CDI_grid_type\"]=\"unstructured\"\n", "coordlist=[\"vertices_latitude\", \"vertices_longitude\", \"lat_bnds\", \"lon_bnds\"]\n", "dset=dset.set_coords([coord for coord in dset.data_vars if coord in coordlist])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "psy.plot.mapplot(\n", " dset, name=\"tos\", cmap='rainbow',\n", " lonlatbox='Ireland',\n", " clabel=dset[\"tos\"].description,\n", " stock_img=True,\n", " lsm='50m',\n", " datagrid=dict(c='b', lw=0.2)).show()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "dset.close()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Used data\n", "\n", "- [Semmler et al., 2019: AWI AWI-CM1.1MR model output prepared for CMIP6](https://doi.org/10.22033/ESGF/CMIP6.2803)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We acknowledge the CMIP community for providing the climate model data, retained and globally distributed in the framework of the ESGF. The CMIP data of this study were replicated and made available for this study by the DKRZ.”" ] } ], "metadata": { "kernelspec": { "display_name": "python3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.12" } }, "nbformat": 4, "nbformat_minor": 4 }