{ "cells": [ { "cell_type": "markdown", "id": "26038f28", "metadata": { "execution": {} }, "source": [ "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/neuromatch/climate-course-content/blob/main/tutorials/W1D1_ClimateSystemOverview/student/W1D1_Tutorial4.ipynb)   \"Open" ] }, { "cell_type": "markdown", "id": "NJh_iuR-5DFi", "metadata": { "execution": {} }, "source": [ "# Tutorial 4: Arithmetic and Aggregation Methods\n", "\n", "**Week 1, Day 1, Climate System Overview**\n", "\n", "**Content creators:** Sloane Garelick, Julia Kent\n", "\n", "**Content reviewers:** Katrina Dobson, Younkap Nina Duplex, Danika Gupta, Maria Gonzalez, Will Gregory, Nahid Hasan, Paul Heubel, Sherry Mi, Beatriz Cosenza Muralles, Jenna Pearson, Agustina Pesce, Chi Zhang, Ohad Zivan\n", "\n", "**Content editors:** Paul Heubel, Jenna Pearson, Chi Zhang, Ohad Zivan\n", "\n", "**Production editors:** Wesley Banfield, Paul Heubel, Jenna Pearson, Konstantine Tsafatinos, Chi Zhang, Ohad Zivan\n", "\n", "**Our 2024 Sponsors:** CMIP, NFDI4Earth" ] }, { "cell_type": "markdown", "id": "495977ba-44ab-489d-ad27-1ddba8228aec", "metadata": { "execution": {} }, "source": [ "## ![project pythia](https://projectpythia.org/_static/images/logos/pythia_logo-blue-rtext.svg)\n", "\n", "Pythia credit: Rose, B. E. J., Kent, J., Tyle, K., Clyne, J., Banihirwe, A., Camron, D., May, R., Grover, M., Ford, R. R., Paul, K., Morley, J., Eroglu, O., Kailyn, L., & Zacharias, A. (2023). Pythia Foundations (Version v2023.05.01) https://zenodo.org/record/8065851\n", "\n", "## ![CMIP.png](https://github.com/ClimateMatchAcademy/course-content/blob/main/tutorials/Art/CMIP.png?raw=true)\n" ] }, { "cell_type": "markdown", "id": "Lcbp0S4xhClA", "metadata": { "execution": {} }, "source": [ "# Tutorial Objectives\n", "\n", "*Estimated timing of tutorial:* 25 minutes \n", "\n", "As we just learned in the video, alongside the latitudinal temperature gradients set by solar radiation, the large-scale ocean circulation patterns are one of the main controls on global sea surface temperature (SST, or tos). The surface currents distort this meridional gradient and can transport heat globally. In this tutorial, we'll use a series of tools in Xarray to interpret sea surface temperature data. \n", "\n", "Specifically, we’ll import monthly SST data from the Community Earth System Model v2 (CESM2), which is a Global Climate Model. A climate model is a mathematical representation of Earth's climate system components and their interactions. Climate models are based on well-documented physical processes to simulate the transfer of energy and materials through the climate system. You'll learn more about climate models later this week and next week, but for now, we're going to be working with SST data produced from a climate model. \n", "\n", "To assess global variations in this SST dataset, we will practice using multiple attributes of Xarray:\n", "\n", "\n", "* Arithmetic methods to convert temperatures from Celsius to Kelvin\n", "* Aggregation methods to calculate mean, median, minimum, and maximum values of the data.\n", "\n", "\n", "Finally, we'll create a map of global mean annual SST to visualize spatial variations in SST.\n" ] }, { "cell_type": "markdown", "id": "0af7bee1-3de3-453a-8ae8-bcd7910b4266", "metadata": { "execution": {}, "tags": [] }, "source": [ "# Setup\n" ] }, { "cell_type": "code", "execution_count": null, "id": "5e22563d-1148-4079-9f92-5f2e780b9119", "metadata": { "execution": {} }, "outputs": [], "source": [ "# installations ( uncomment and run this cell ONLY when using google colab or kaggle )\n", "#!pip install pythia_datasets" ] }, { "cell_type": "code", "execution_count": null, "id": "06073287-7bdb-45b5-9cec-8cdf123adb49", "metadata": { "execution": {}, "tags": [] }, "outputs": [], "source": [ "# imports\n", "import xarray as xr\n", "from pythia_datasets import DATASETS\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Figure Settings\n" ] }, { "cell_type": "code", "execution_count": null, "id": "ed6bcdfe-d18b-42a4-96d6-2f921d9ce3fd", "metadata": { "cellView": "form", "execution": {}, "tags": [ "hide-input" ] }, "outputs": [], "source": [ "# @title Figure Settings\n", "import ipywidgets as widgets # interactive display\n", "\n", "%config InlineBackend.figure_format = 'retina'\n", "plt.style.use(\n", " \"https://raw.githubusercontent.com/neuromatch/climate-course-content/main/cma.mplstyle\"\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Video 1: Oceanic Climate Systems\n" ] }, { "cell_type": "code", "execution_count": null, "id": "1712a218-1c6b-4ae9-9b89-5843bdde1d96", "metadata": { "cellView": "form", "execution": {}, "tags": [ "remove-input" ] }, "outputs": [], "source": [ "# @title Video 1: Oceanic Climate Systems\n", "\n", "from ipywidgets import widgets\n", "from IPython.display import YouTubeVideo\n", "from IPython.display import IFrame\n", "from IPython.display import display\n", "\n", "\n", "class PlayVideo(IFrame):\n", " def __init__(self, id, source, page=1, width=400, height=300, **kwargs):\n", " self.id = id\n", " if source == 'Bilibili':\n", " src = f'https://player.bilibili.com/player.html?bvid={id}&page={page}'\n", " elif source == 'Osf':\n", " src = f'https://mfr.ca-1.osf.io/render?url=https://osf.io/download/{id}/?direct%26mode=render'\n", " super(PlayVideo, self).__init__(src, width, height, **kwargs)\n", "\n", "\n", "def display_videos(video_ids, W=400, H=300, fs=1):\n", " tab_contents = []\n", " for i, video_id in enumerate(video_ids):\n", " out = widgets.Output()\n", " with out:\n", " if video_ids[i][0] == 'Youtube':\n", " video = YouTubeVideo(id=video_ids[i][1], width=W,\n", " height=H, fs=fs, rel=0)\n", " print(f'Video available at https://youtube.com/watch?v={video.id}')\n", " else:\n", " video = PlayVideo(id=video_ids[i][1], source=video_ids[i][0], width=W,\n", " height=H, fs=fs, autoplay=False)\n", " if video_ids[i][0] == 'Bilibili':\n", " print(f'Video available at https://www.bilibili.com/video/{video.id}')\n", " elif video_ids[i][0] == 'Osf':\n", " print(f'Video available at https://osf.io/{video.id}')\n", " display(video)\n", " tab_contents.append(out)\n", " return tab_contents\n", "\n", "\n", "video_ids = [('Youtube', 'E3UEWlak5Zs'), ('Bilibili', 'BV1gz4y177vk')]\n", "tab_contents = display_videos(video_ids, W=730, H=410)\n", "tabs = widgets.Tab()\n", "tabs.children = tab_contents\n", "for i in range(len(tab_contents)):\n", " tabs.set_title(i, video_ids[i][0])\n", "display(tabs)" ] }, { "cell_type": "code", "execution_count": null, "id": "682c6f71-edc2-4088-bd74-fb526e667ba7", "metadata": { "cellView": "form", "execution": {}, "pycharm": { "name": "#%%\n" }, "tags": [ "remove-input" ] }, "outputs": [], "source": [ "# @markdown\n", "from ipywidgets import widgets\n", "from IPython.display import IFrame\n", "\n", "link_id = \"hmqfr\"\n", "\n", "download_link = f\"https://osf.io/download/{link_id}/\"\n", "render_link = f\"https://mfr.ca-1.osf.io/render?url=https://osf.io/{link_id}/?direct%26mode=render%26action=download%26mode=render\"\n", "# @markdown\n", "out = widgets.Output()\n", "with out:\n", " print(f\"If you want to download the slides: {download_link}\")\n", " display(IFrame(src=f\"{render_link}\", width=730, height=410))\n", "display(out)" ] }, { "cell_type": "markdown", "id": "b3f4e108-f55e-4c25-a00d-99dc00ba849a", "metadata": { "execution": {}, "tags": [] }, "source": [ "# Section 1: Arithmetic Operations\n", "\n", "Arithmetic operations with a single `DataArray` automatically apply over all array values (like NumPy). This process is called **vectorization**. First, let's open the monthly sea surface temperature (SST) data from the Community Earth System Model v2 (CESM2), which is a Global Climate Model." ] }, { "cell_type": "code", "execution_count": null, "id": "7837f8bd-da89-4718-ab02-d5107576d2d6", "metadata": { "execution": {}, "executionInfo": { "elapsed": 303, "status": "ok", "timestamp": 1681569406112, "user": { "displayName": "Sloane Garelick", "userId": "04706287370408131987" }, "user_tz": 240 }, "tags": [] }, "outputs": [], "source": [ "filepath = DATASETS.fetch(\"CESM2_sst_data.nc\")\n", "ds = xr.open_dataset(filepath)\n", "ds" ] }, { "cell_type": "markdown", "id": "8cabb77f", "metadata": { "execution": {} }, "source": [ "And look at the temperature variable `tos`." ] }, { "cell_type": "code", "execution_count": null, "id": "cbe80157", "metadata": { "execution": {} }, "outputs": [], "source": [ "ds.tos" ] }, { "cell_type": "markdown", "id": "6a185c07", "metadata": { "execution": {} }, "source": [ "Note in the attributes that the units are `degC`. One arithmetic operation we can do is to convert the temperature from degrees Celsius to Kelvin:" ] }, { "cell_type": "code", "execution_count": null, "id": "09542eab-998d-4b2d-807c-dccd5bd4329e", "metadata": { "execution": {}, "executionInfo": { "elapsed": 14, "status": "ok", "timestamp": 1681569533895, "user": { "displayName": "Sloane Garelick", "userId": "04706287370408131987" }, "user_tz": 240 }, "tags": [] }, "outputs": [], "source": [ "ds.tos + 273.15" ] }, { "cell_type": "markdown", "id": "6f35c8d6-b0e6-4371-ad80-e182ffcec51b", "metadata": { "execution": {} }, "source": [ "\n", "You may notice that there are a lot of NaN values in the DataArray for `tos`. NaN isn’t a bad thing and it just means there isn’t data for those coordinates. In this case, there's no `tos` data for areas with land since this dataset only contains SST values.\n", "\n", "\n", "Just to practice another arithmetic operation, let's square all values in `tos`:" ] }, { "cell_type": "code", "execution_count": null, "id": "78c1ffc2-45cb-40cc-962e-c76021d9ab1c", "metadata": { "execution": {}, "executionInfo": { "elapsed": 12, "status": "ok", "timestamp": 1681569537428, "user": { "displayName": "Sloane Garelick", "userId": "04706287370408131987" }, "user_tz": 240 }, "tags": [] }, "outputs": [], "source": [ "ds.tos**2" ] }, { "cell_type": "markdown", "id": "0bebb17b-6906-4ba7-a4ff-c07a9206e790", "metadata": { "execution": {}, "tags": [] }, "source": [ "# Section 2: Aggregation Methods\n", "\n", "A very common step during data analysis is to summarize the data in question by computing aggregations like `.sum()`, `.mean()`, `.median()`, `.min()`, `.max()` in which reduced data provide insight into the nature of the large dataset. For example, in the introductory video for this tutorial, we saw maps of the mean annual sea surface temperature and sea surface density. \n", "\n", "\n", "The following table summarizes some other built-in Xarray aggregations:\n", "\n", "| Aggregation | Description |\n", "|--------------------------|---------------------------------|\n", "| ``.count()`` | Total number of items |\n", "| ``.mean()``, ``.median()`` | Mean and median |\n", "| ``.min()``, ``.max()`` | Minimum and maximum |\n", "| ``.std()``, ``.var()`` | Standard deviation and variance |\n", "| ``.prod()`` | Compute product of elements |\n", "| ``.sum()`` | Compute sum of elements |\n", "| ``.argmin()``, ``.argmax()``| Find index of minimum and maximum value |\n", "\n", "\n", "Let's explore some of these aggregation methods.\n" ] }, { "cell_type": "markdown", "id": "e6f15eca", "metadata": { "execution": {} }, "source": [ "Compute the temporal minimum:" ] }, { "cell_type": "code", "execution_count": null, "id": "06e3bfff", "metadata": { "execution": {}, "tags": [] }, "outputs": [], "source": [ "ds.tos.min(dim=\"time\")" ] }, { "cell_type": "markdown", "id": "01bfdf21", "metadata": { "execution": {} }, "source": [ "Compute the spatial sum:" ] }, { "cell_type": "code", "execution_count": null, "id": "400c3dab", "metadata": { "execution": {}, "tags": [] }, "outputs": [], "source": [ "ds.tos.sum(dim=[\"lat\", \"lon\"])" ] }, { "cell_type": "markdown", "id": "e8bd66b3", "metadata": { "execution": {} }, "source": [ "Compute the temporal median:" ] }, { "cell_type": "code", "execution_count": null, "id": "5d397f30", "metadata": { "execution": {}, "tags": [] }, "outputs": [], "source": [ "ds.tos.median(dim=\"time\")" ] }, { "cell_type": "markdown", "id": "a4d79093-f013-4821-84f8-3c223141046e", "metadata": { "execution": {} }, "source": [ "Compute the mean SST:" ] }, { "cell_type": "code", "execution_count": null, "id": "59b84034-7d42-4080-932f-0eefd165953d", "metadata": { "execution": {}, "executionInfo": { "elapsed": 297, "status": "ok", "timestamp": 1681569542731, "user": { "displayName": "Sloane Garelick", "userId": "04706287370408131987" }, "user_tz": 240 }, "tags": [] }, "outputs": [], "source": [ "ds.tos.mean()" ] }, { "cell_type": "markdown", "id": "a75e0064-4363-4328-9a79-d87475ed1c81", "metadata": { "execution": {} }, "source": [ "Because we specified no `dim` argument, the function was applied over all dimensions, computing the mean of every element of `tos` across time and space. It is possible to specify a dimension along which to compute an aggregation. For example, to calculate the mean in time for all locations (i.e. the global mean annual SST), specify the time dimension as the dimension along which the mean should be calculated:" ] }, { "cell_type": "code", "execution_count": null, "id": "a49b957e-ea24-414e-a422-c40a3723fbae", "metadata": { "execution": {}, "executionInfo": { "elapsed": 815, "status": "ok", "timestamp": 1681569338417, "user": { "displayName": "Sloane Garelick", "userId": "04706287370408131987" }, "user_tz": 240 }, "tags": [] }, "outputs": [], "source": [ "# Note how we chain the mean() and plot() methods, which get executed from left to right\n", "ds.tos.mean(dim=\"time\").plot(size=7, vmin=-2, vmax=32, cmap=\"coolwarm\")" ] }, { "cell_type": "markdown", "id": "aVnchVimEp6k", "metadata": { "execution": {} }, "source": [ "### Questions 2: Climate Connection\n", "\n", "Observe the spatial patterns in SST and consider the following in the context of the components of the ocean climate system we learned about in the video:\n", "\n", "1. Recall that upwelling commonly occurs off the west coast of continents, for example, in the eastern tropical Pacific off the west coast of South America. Do you see evidence for upwelling in this region? How do you think the mean SST in this region would change if you looked at a specific season rather than the annual mean? Would upwelling be more or less evident?\n" ] }, { "cell_type": "markdown", "id": "589b4cf2-9431-43e9-ad76-9acbc7bde892", "metadata": { "colab_type": "text", "execution": {}, "tags": [] }, "source": [ "[*Click for solution*](https://github.com/neuromatch/climate-course-content/tree/main/tutorials/W1D1_ClimateSystemOverview/solutions/W1D1_Tutorial4_Solution_6ce26e59.py)\n", "\n" ] }, { "cell_type": "markdown", "id": "9ac2925a-9b96-4b0a-b2b6-24f6b4151d4c", "metadata": { "execution": {} }, "source": [ "# Summary\n", "\n", "In this tutorial, we have explored the use of the CESM2 and have imported and analyzed monthly sea surface temperature (SST, or tos) data. We used arithmetic methods to convert SST from Celsius to Kelvin, and aggregation methods such as the mean, median, minimum, and maximum values of the data. To conclude, we visualized the spatial variations in SST by generating a map of the global mean annual SST. This tutorial has provided us with valuable insights into global variations in SST and how to manipulate and analyze such data using Xarray.\n" ] }, { "cell_type": "markdown", "id": "de7bca95-3766-4bd0-b5dd-a82683f0732a", "metadata": { "execution": {} }, "source": [ "# Resources" ] }, { "cell_type": "markdown", "id": "5f41d4b4-5929-4418-b8d4-d8ef60326899", "metadata": { "execution": {} }, "source": [ "Code and data for this tutorial is based on existing content from [Project Pythia](https://foundations.projectpythia.org/core/xarray/computation-masking.html)." ] } ], "metadata": { "colab": { "collapsed_sections": [], "include_colab_link": true, "name": "W1D1_Tutorial4", "provenance": [], "toc_visible": true }, "kernel": { "display_name": "Python 3", "language": "python", "name": "python3" }, "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.9.19" } }, "nbformat": 4, "nbformat_minor": 5 }