{ "cells": [ { "cell_type": "markdown", "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/W1D5_IntroductiontoClimateModeling/instructor/W1D5_Tutorial6.ipynb)   \"Open" ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "# Bonus Tutorial 6: Radiative-Convective Equilibrium\n", "\n", "\n", "**Week 1, Day 5, Introduction to Climate Modeling**\n", "\n", "**Content creators:** Jenna Pearson and Brian E. J. Rose\n", "\n", "**Content reviewers:** Mujeeb Abdulfatai, Nkongho Ayuketang Arreyndip, Jeffrey N. A. Aryee, Younkap Nina Duplex, Will Gregory, Paul Heubel, Zahra Khodakaramimaghsoud, Peter Ohue, Abel Shibu, Derick Temfack, Yunlong Xu, Peizhen Yang, Ohad Zivan, Chi Zhang\n", "\n", "**Content editors:** Abigail Bodner, Paul Heubel, Brodie Pearson, Ohad Zivan, Chi Zhang\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", "metadata": { "execution": {} }, "source": [ "# Tutorial Objectives\n", "\n", "*Estimated timing of tutorial:* 20 minutes\n", "\n", "*Note that this and the two previous tutorials contain solely Bonus content that serves experienced participants and for later investigation of 0- and 1-dimensional models after the course. Please check out these tutorials after finishing Tutorial 7-8 successfully*.\n", "\n", "Building on the understanding of a one-dimensional radiative balance model from the previous tutorial, in this tutorial you will learn about **radiative-convective-equilibrium**. Much of the code shown here was taken from [The Climate Laboratory](https://brian-rose.github.io/ClimateLaboratoryBook/home.html) by Brian E. J. Rose. You are encouraged to visit this website for more tutorials and background on these models.\n", "\n", "By the end of this tutorial you will be able to:\n", "* Implement a radiative-convective equilibrium model using the python package `climlab`.\n", "* Understand how this model builds off the one-dimensional radiative balance model used in the previous tutorials." ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "# Setup" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {}, "executionInfo": { "elapsed": 161558, "status": "ok", "timestamp": 1682124783292, "user": { "displayName": "Jenna Pearson", "userId": "05648130581702734913" }, "user_tz": 420 }, "tags": [ "colab" ] }, "outputs": [], "source": [ "# installations ( uncomment and run this cell ONLY when using google colab or kaggle )\n", "\n", "# note the conda install takes quite a while, but conda is REQUIRED to properly download the\n", "# dependencies (that are not just python packages)\n", "\n", "# !pip install condacolab &> /dev/null\n", "# import condacolab\n", "# condacolab.install()\n", "\n", "# !mamba install -c anaconda cftime xarray numpy &> /dev/null # for decoding time variables when opening datasets\n", "# !mamba install -c conda-forge metpy climlab &> /dev/null" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {}, "executionInfo": { "elapsed": 10496, "status": "ok", "timestamp": 1682124802202, "user": { "displayName": "Jenna Pearson", "userId": "05648130581702734913" }, "user_tz": 420 } }, "outputs": [], "source": [ "# imports\n", "\n", "# google colab users, if you get an xarray error, please run this cell again\n", "\n", "import xarray as xr # used to manipulate data and open datasets\n", "import numpy as np # used for algebra/arrays\n", "import climlab # one of the models we are using\n", "import matplotlib.pyplot as plt # used for plotting\n", "import metpy # used to make Skew T Plots of temperature and pressure\n", "from metpy.plots import SkewT # plotting function used widely in climate science\n", "import pooch\n", "import os\n", "import tempfile\n", "from IPython.display import HTML\n", "from matplotlib import animation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Install and import feedback gadget\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "cellView": "form", "execution": {}, "tags": [ "hide-input" ] }, "outputs": [], "source": [ "# @title Install and import feedback gadget\n", "\n", "!pip3 install vibecheck datatops --quiet\n", "\n", "from vibecheck import DatatopsContentReviewContainer\n", "def content_review(notebook_section: str):\n", " return DatatopsContentReviewContainer(\n", " \"\", # No text prompt\n", " notebook_section,\n", " {\n", " \"url\": \"https://pmyvdlilci.execute-api.us-east-1.amazonaws.com/klab\",\n", " \"name\": \"comptools_4clim\",\n", " \"user_key\": \"l5jpxuee\",\n", " },\n", " ).render()\n", "\n", "\n", "feedback_prefix = \"W1D5_T6\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Figure settings\n" ] }, { "cell_type": "code", "execution_count": null, "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": [ "## Helper functions\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "cellView": "form", "execution": {}, "tags": [ "hide-input" ] }, "outputs": [], "source": [ "# @title Helper functions\n", "\n", "def pooch_load(filelocation=None, filename=None, processor=None):\n", " shared_location = \"/home/jovyan/shared/Data/tutorials/W1D5_IntroductiontoClimateModeling\" # this is different for each day\n", " user_temp_cache = tempfile.gettempdir()\n", "\n", " if os.path.exists(os.path.join(shared_location, filename)):\n", " file = os.path.join(shared_location, filename)\n", " else:\n", " file = pooch.retrieve(\n", " filelocation,\n", " known_hash=None,\n", " fname=os.path.join(user_temp_cache, filename),\n", " processor=processor,\n", " )\n", "\n", " return file" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plotting Functions\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "cellView": "form", "execution": {}, "executionInfo": { "elapsed": 5, "status": "ok", "timestamp": 1682124802203, "user": { "displayName": "Jenna Pearson", "userId": "05648130581702734913" }, "user_tz": 420 }, "tags": [ "hide-input" ] }, "outputs": [], "source": [ "# @title Plotting Functions\n", "\n", "# make the videos at the end of the tutorial\n", "plt.rcParams[\"animation.html\"] = \"jshtml\"\n", "\n", "# these three functions are used to make videos at the end of the tutorial\n", "\n", "\n", "def initial_figure(model):\n", " with plt.ioff(): # will hide the inital figure which will plot separate from the video otherwise\n", " fig = plt.figure(figsize=(6, 6))\n", " lines = []\n", "\n", " skew = SkewT(fig, rotation=30)\n", " # plot the observations\n", " skew.plot(\n", " Tglobal.level,\n", " Tglobal,\n", " color=\"black\",\n", " linestyle=\"-\",\n", " linewidth=2,\n", " label=\"Observations\",\n", " )\n", " lines.append(\n", " skew.plot(\n", " model.lev,\n", " model.Tatm - climlab.constants.tempCtoK,\n", " linestyle=\"-\",\n", " linewidth=2,\n", " color=\"C0\",\n", " label=\"RC model (all gases)\",\n", " )[0]\n", " )\n", " skew.ax.legend()\n", " skew.ax.set_ylim(1050, 10)\n", " skew.ax.set_xlim(-60, 75)\n", " # Add the relevant special lines\n", " skew.plot_dry_adiabats(linewidth=1.5, label=\"dry adiabats\")\n", " # skew.plot_moist_adiabats(linewidth=1.5, label = 'moist adiabats')\n", " skew.ax.set_xlabel(\"Temperature ($^\\circ$C)\", fontsize=14)\n", " skew.ax.set_ylabel(\"Pressure (hPa)\", fontsize=14)\n", " lines.append(\n", " skew.plot(\n", " 1000,\n", " model.Ts - climlab.constants.tempCtoK,\n", " \"o\",\n", " markersize=8,\n", " color=\"C0\",\n", " )[0]\n", " )\n", "\n", " return fig, lines\n", "\n", "\n", "def animate(day, model, lines):\n", " lines[0].set_xdata(np.array(model.Tatm) - climlab.constants.tempCtoK)\n", " lines[1].set_xdata(np.array(model.Ts) - climlab.constants.tempCtoK)\n", " # lines[2].set_xdata(np.array(model.q)*1E3)\n", " # lines[-1].set_text('Day {}'.format(int(model.time['days_elapsed'])))\n", " # This is kind of a hack, but without it the initial frame doesn't appear\n", " if day != 0:\n", " model.step_forward()\n", " return lines\n", "\n", "\n", "# to setup the skewT and plot observations\n", "def make_basic_skewT():\n", " fig = plt.figure(figsize=(9, 9))\n", " skew = SkewT(fig, rotation=30)\n", " skew.plot(\n", " Tglobal.level,\n", " Tglobal,\n", " color=\"black\",\n", " linestyle=\"-\",\n", " linewidth=2,\n", " label=\"Observations\",\n", " )\n", " skew.ax.set_ylim(1050, 10)\n", " skew.ax.set_xlim(-90, 45)\n", " # Add the relevant special lines\n", " # skew.plot_dry_adiabats(linewidth=1.5, label = 'dry adiabats')\n", " # skew.plot_moist_adiabats(linewidth=1.5, label = 'moist adiabats')\n", " # skew.plot_mixing_lines()\n", " skew.ax.legend()\n", " skew.ax.set_xlabel(\"Temperature (degC)\", fontsize=14)\n", " skew.ax.set_ylabel(\"Pressure (hPa)\", fontsize=14)\n", " return skew\n", "\n", "\n", "# to setup the skewT and plot observations\n", "def make_skewT():\n", " fig = plt.figure(figsize=(9, 9))\n", " skew = SkewT(fig, rotation=30)\n", " skew.plot(\n", " Tglobal.level,\n", " Tglobal,\n", " color=\"black\",\n", " linestyle=\"-\",\n", " linewidth=2,\n", " label=\"Observations\",\n", " )\n", " skew.ax.set_ylim(1050, 10)\n", " skew.ax.set_xlim(-90, 45)\n", " # Add the relevant special lines\n", " skew.plot_dry_adiabats(linewidth=1.5, label=\"dry adiabats\")\n", " # skew.plot_moist_adiabats(linewidth=1.5, label = 'moist adiabats')\n", " # skew.plot_mixing_lines()\n", " skew.ax.legend()\n", " skew.ax.set_xlabel(\"Temperature (degC)\", fontsize=14)\n", " skew.ax.set_ylabel(\"Pressure (hPa)\", fontsize=14)\n", " return skew\n", "\n", "\n", "# to add a model derived profile to the skewT figure\n", "def add_profile(skew, model, linestyle=\"-\", color=None):\n", " line = skew.plot(\n", " model.lev,\n", " model.Tatm - climlab.constants.tempCtoK,\n", " label=model.name,\n", " linewidth=2,\n", " )[0]\n", " skew.plot(\n", " 1000,\n", " model.Ts - climlab.constants.tempCtoK,\n", " \"o\",\n", " markersize=8,\n", " color=line.get_color(),\n", " )\n", " skew.ax.legend()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Video 1: Radiative-Convective Equilibrium\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "cellView": "form", "execution": {}, "tags": [ "remove-input" ] }, "outputs": [], "source": [ "# @title Video 1: Radiative-Convective Equilibrium\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', 'KV198mGq1GM'), ('Bilibili', 'BV1gP411Q7f3')]\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": "markdown", "metadata": {}, "source": [ "## Submit your feedback\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "cellView": "form", "execution": {}, "tags": [ "hide-input" ] }, "outputs": [], "source": [ "# @title Submit your feedback\n", "content_review(f\"{feedback_prefix}_Radiative_Convective_Equilibrium_Video\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n" ] }, { "cell_type": "code", "execution_count": null, "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 = \"msarf\"\n", "\n", "print(f\"If you want to download the slides: https://osf.io/download/{link_id}/\")\n", "IFrame(src=f\"https://mfr.ca-1.osf.io/render?url=https://osf.io/{link_id}/?direct%26mode=render%26action=download%26mode=render\", width=854, height=480)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Submit your feedback\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "cellView": "form", "execution": {}, "tags": [ "hide-input" ] }, "outputs": [], "source": [ "# @title Submit your feedback\n", "content_review(f\"{feedback_prefix}_Radiative_Convective_Equilibrium_Slides\")" ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "# Section 1: Reproducing Data from the Last Tutorial's One-dimensional Radiative Equilibrium Model Using Climlab\n", "\n", "Please refer to the previous Bonus Tutorial 6 for a refresher if needed." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {} }, "outputs": [], "source": [ "filename_sq = \"cpl_1850_f19-Q-gw-only.cam.h0.nc\"\n", "url_sq = \"https://osf.io/c6q4j/download/\"\n", "ds = xr.open_dataset(\n", " pooch_load(filelocation=url_sq, filename=filename_sq)\n", ") # ds = dataset\n", "\n", "filename_ncep_air = \"air.mon.1981-2010.ltm.nc\"\n", "url_ncep_air = \"https://osf.io/w6cd5/download/\"\n", "ncep_air = xr.open_dataset(\n", " pooch_load(filelocation=url_ncep_air, filename=filename_ncep_air)\n", ") # ds = dataset\n", "\n", "# take global, annual average of specific humidity\n", "weight_factor = ds.gw / ds.gw.mean(dim=\"lat\")\n", "Qglobal = (ds.Q * weight_factor).mean(dim=(\"lat\", \"lon\", \"time\"))\n", "\n", "# use 'lev=Qglobal.lev' to create an identical vertical grid to water vapor data\n", "mystate = climlab.column_state(lev=Qglobal.lev, water_depth=2.5)\n", "\n", "radmodel = climlab.radiation.RRTMG(\n", " name=\"Radiation (all gases)\", # give our model a name\n", " state=mystate, # give our model an initial condition\n", " specific_humidity=Qglobal.values, # tell the model how much water vapor there is\n", " albedo=0.25, # set the SURFACE shortwave albedo\n", " timestep=climlab.constants.seconds_per_day, # set the timestep to one day (measured in seconds)\n", ")\n", "\n", "# need to take the average over space and time\n", "# the grid cells are not the same size moving towards the poles, so we weight by the cosine of latitude to compensate for this\n", "coslat = np.cos(np.deg2rad(ncep_air.lat))\n", "weight = coslat / coslat.mean(dim=\"lat\")\n", "\n", "# global mean temperature from NCEP\n", "Tglobal = (ncep_air.air * weight).mean(dim=(\"lat\", \"lon\", \"time\"))\n", "\n", "# take a single step forward until the diagnostics are updated and there is some energy imbalance\n", "radmodel.step_forward()\n", "\n", "# run the model to equilibrium (the difference between ASR and OLR is a very small number)\n", "while np.abs(radmodel.ASR - radmodel.OLR) > 0.001:\n", " radmodel.step_forward()\n", "\n", "skew = make_basic_skewT()\n", "add_profile(skew, radmodel)\n", "skew.ax.set_title(\"Pure Radiative Equilibrium\")" ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "# Section 2: Radiative-Convective Equilibrium" ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "From the plot you just made, one of the largest differences between observations and the pure radiation model with all gases lies in the lower atmosphere, where the surface air temperature is 20 degrees too warm and the 200 hPa pressure surface is 40 degrees too cold. What could be the issue?\n", "\n", "One thing we have not included in our model yet is dynamics (motion of the air). The model's temperature profile is what's known as **statically unstable** (note this definition of stability is different than that used in the previous tutorials).\n", "\n", "Here **static** means not due to wind, and **unstable** means the atmosphere wants to adjust to a different state because the surface air is relatively light and wants to rise into upper layers of the atmosphere. As the air rises, it creates **convective turbulence** (similar to boiling water, where convective circulation is introduced by heating water from below). The rising air, and the resultant turbulence, mixes the atmospheric column. This mixing often occurs across the **troposphere**, which is roughly the lowest $10 \\text{ km}$ of the atmosphere. Most of the weather we experience lies in the troposphere. \n", "\n", "When air rises **[adiabatically](https://glossary.ametsoc.org/wiki/Adiabatic_process)**, it expands and cools due to the lower pressure. The *rate* of cooling depends on whether the air is saturated with water vapor. When rising air is unsaturated, it cools following the dry adiabats. If the air saturates, it cools at a lesser rate denoted by the moist adiabats (we did not have time to discuss these moisture effects in the mini-lecture). \n", "\n", "To identify unstable atmospheric layers, let's take another look at the SkewT plot, but this time we will plot the dry adiabats. We can then compare the rates of cooling of our model to these adiabats." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {}, "executionInfo": { "elapsed": 1707, "status": "ok", "timestamp": 1680662835097, "user": { "displayName": "Jenna Pearson", "userId": "05648130581702734913" }, "user_tz": 420 } }, "outputs": [], "source": [ "skew = make_skewT()\n", "add_profile(skew, radmodel)\n", "skew.ax.set_title(\"Pure Radiative Equilibrium\")" ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "\n", "Near the surface, the reanalysis temperature profile is steeper than the dry adiabats. In these layers vertical motion is inhibited, and the surface conditions are considered stable. However, the model profile is shallower than the dry adiabats. In the model, the surface air is *statically unstable*, which would lead to convective mixing if this physical process was included in the model (the model currently only includes radiative processes). **In this tutorial we will see whether including convective mixing in our model can bring the model closer to the reanalysis temperature profile.**\n", "\n", "To build a radiative-convective model we can take the radiative model we have already made and couple it to a convective model. Here the term **couple** implies there is communication between the models such that their effects are both incorporated into the final product, which in our case is the temperature profile." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {} }, "outputs": [], "source": [ "# restate the model here for ease of coding\n", "\n", "# make a model on same vertical domain as the water vapor data\n", "mystate = climlab.column_state(lev=Qglobal.lev, water_depth=2.5)\n", "\n", "# create the radiation model\n", "rad = climlab.radiation.RRTMG(\n", " name=\"Radiation (net)\",\n", " state=mystate,\n", " specific_humidity=Qglobal.values,\n", " timestep=climlab.constants.seconds_per_day,\n", " albedo=0.25, # surface albedo, tuned to give reasonable ASR for reference cloud-free model\n", ")\n", "\n", "# create the convection model\n", "conv = climlab.convection.ConvectiveAdjustment(\n", " name=\"Convection\",\n", " state=mystate,\n", " adj_lapse_rate=6.5, # the adiabatic lapse rate of the atmopshere\n", " timestep=rad.timestep, # same timestep as radiation model\n", ")\n", "# couple the two components\n", "rcm = climlab.couple([rad, conv], name=\"Radiative-Convective Model\")" ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "Now let's run the radiation part to equilibrium, which should give us the same profile as in the previous section. Once we get this *radiative equilibrium* profile we will add convective mixing physics to the model and continue running it until it reaches *radiative-convective equilibrium*.\n", "\n", "The new model does not actually resolve the actual vertical motion and mixing that occurs in convection. Instead, the model includes a *parameterization* for convection which automatically mixes regions of the atmospheric column that are statically unstable." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {}, "executionInfo": { "elapsed": 8446, "status": "ok", "timestamp": 1680662843889, "user": { "displayName": "Jenna Pearson", "userId": "05648130581702734913" }, "user_tz": 420 } }, "outputs": [], "source": [ "# run JUST the radiative component to equilibrium\n", "for n in range(1000):\n", " rcm.subprocess[\"Radiation (net)\"].step_forward()\n", "\n", "# compute diagnostics\n", "rcm.compute_diagnostics()\n", "\n", "# plot the resulting profile (our initial condition once we turn on the physics)\n", "fig, lines = initial_figure(rcm)\n", "\n", "# this animation can take a while\n", "animation.FuncAnimation(fig, animate, 50, fargs=(rcm, lines))" ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "Adding convective mixing to the initially unstable temperature profile leads to an instant mixing of air throughout the lower atmosphere, moving the profile toward the observations. The balance at play is between radiative processes that warm the surface and cool the troposphere (lower atmosphere) as well as convection which moves heat away from the surface, leading to a colder surface and warmer troposphere. Note the differences in surface versus tropospheric temperatures in the new versus old equilibrium profiles." ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "## Questions 2: Climate Connection" ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "1. The static instability was removed in the first time step! In reality, which process do you think changes temperature faster, convection or radiation?\n", "2. What do you think the next step would be to move towards a more realistic climate model?" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {} }, "outputs": [], "source": [ "# to_remove explanation\n", "\n", "\"\"\"\n", "1. In nature, convection changes the temperature of the atmospheric column faster than radiative processes because convection involves the quick movement of air (and heat) from one place to another. Our model takes this into account by having convective processes act instantaneously on instabilities due to unstable temperature profiles.\n", "2. Next steps could include expanding in space (x,y,z) and including other processes (such as dynamics) and additional components of the climate system (ocean, etc.). We'll talk about this more in Tutorial 7 where you will work with the Taiwan Earth System Model (TaiESM1).\n", "\"\"\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Submit your feedback\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "cellView": "form", "execution": {}, "tags": [ "hide-input" ] }, "outputs": [], "source": [ "# @title Submit your feedback\n", "content_review(f\"{feedback_prefix}_Questions_2\")" ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "## Coding Exercises 2" ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "1. Recreate the video above except using an isothermal atmosphere (uniform temperature profile) set to the surface temperature `rcm.state.Ts`. Does the equilbrium profile look any different than the one you made before?" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "execution": {}, "executionInfo": { "elapsed": 16, "status": "ok", "timestamp": 1680662920103, "user": { "displayName": "Jenna Pearson", "userId": "05648130581702734913" }, "user_tz": 420 } }, "source": [ "```python\n", "# set initial temperature profile to be the surface temperature (isothermal)\n", "rcm.state.Tatm[:] = rcm.state.Ts\n", "\n", "# compute diagnostics\n", "_ = ...\n", "\n", "# plot initial data\n", "fig, lines = initial_figure(rcm)\n", "\n", "# make animation - this animation can take a while\n", "# animation.FuncAnimation(fig, animate, 50, fargs=(rcm, lines))\n", "\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {}, "executionInfo": { "elapsed": 2089, "status": "ok", "timestamp": 1680662922186, "user": { "displayName": "Jenna Pearson", "userId": "05648130581702734913" }, "user_tz": 420 } }, "outputs": [], "source": [ "# to_remove solution\n", "\n", "# set initial temperature profile to be the surface temperature (isothermal)\n", "rcm.state.Tatm[:] = rcm.state.Ts\n", "\n", "# compute diagnostics\n", "_ = rcm.compute_diagnostics()\n", "\n", "# plot initial data\n", "fig, lines = initial_figure(rcm)\n", "\n", "# make animation - this animation can take a while\n", "animation.FuncAnimation(fig, animate, 50, fargs=(rcm, lines))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Submit your feedback\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "cellView": "form", "execution": {}, "tags": [ "hide-input" ] }, "outputs": [], "source": [ "# @title Submit your feedback\n", "content_review(f\"{feedback_prefix}_Coding_Exercises_2\")" ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "# Summary\n", "In this tutorial, you explored the concept of radiative-convective equilibrium, learning to implement a Python model using the `climlab` package. You learned the limitations of a pure radiation model and the necessity to include atmospheric dynamics such as convection. Through coupling a radiation model with a convective model, you have simulated a more realistic atmospheric temperature profile. Even though the model does not directly resolve the vertical motion during convection, it incorporates a parameterization to automatically account for mixing in statically unstable regions. By the end of the tutorial, you could comprehend how this model expands on the previous energy balance models from tutorials 1-4." ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "# Resources\n", "\n", "Data from this tutorial can be accessed for specific humidity [here](http://thredds.atmos.albany.edu:8080/thredds/fileServer/CESMA/cpl_1850_f19/concatenated/cpl_1850_f19.cam.h0.nc) and reanalysis temperature [here](https://downloads.psl.noaa.gov/Datasets/ncep.reanalysis/Monthlies/pressure/air.mon.1981-2010.ltm.nc).\n", "\n", "Useful links:\n", "\n", "- [The Climate Laboratory](https://brian-rose.github.io/ClimateLaboratoryBook/home.html) by Brian E. J. Rose,\n", "- [Adiabatic process](https://glossary.ametsoc.org/wiki/Adiabatic_process)." ] } ], "metadata": { "colab": { "collapsed_sections": [], "include_colab_link": true, "name": "W1D5_Tutorial6", "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": 4 }