{ "cells": [ { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/ClimateMatchAcademy/course-content/blob/main/tutorials/W1D5_ClimateModeling/instructor/W1D5_Tutorial5.ipynb)   \"Open" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "# **Tutorial 5: Radiative Equilibrium**\n", "\n", "\n", "**Week 1, Day 5, Climate Modeling**\n", "\n", "**Content creators:** Jenna Pearson\n", "\n", "**Content reviewers:** Yunlong Xu, Will Gregory, Peter Ohue, Derick Temfack, Zahra Khodakaramimaghsoud, Peizhen Yang, Younkap Nina Duplex, Ohad Zivan, Chi Zhang\n", "\n", "**Content editors:** Brodie Pearson, Abigail Bodner, Ohad Zivan, Chi Zhang\n", "\n", "**Production editors:** Wesley Banfield, Jenna Pearson, Chi Zhang, Ohad Zivan\n", "\n", "**Our 2023 Sponsors:** NASA TOPS and Google DeepMind" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "# **Tutorial Objectives**\n", "\n", "In this tutorial students will run a one-dimensional radiative equilibrium model that predicts the global mean atmospheric temperature as a function of height. Much of the code shown here was taken from [The Climate Laboratory](https://brian-rose.github.io/ClimateLaboratoryBook/home.html) by Brian Rose. Students are encouraged to visit this website for more tutorials and background on these models.\n", "\n", "By the end of this tutorial students will be able to:\n", "* Implement a 1-D model that predicts atmospheric temperature as a function of height using the python package `climlab`.\n", "* Understand how this model builds off of the energy balance models developed in the previous tutorials." ] }, { "attachments": {}, "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": [ "# note the conda install takes quite a while, but conda is REQUIRED to properly download the dependencies (that are not just python packages)\n", "# !pip install condacolab &> /dev/null # need to use conda installation of climlab, pip won't work. condacolab is a workaround\n", "# import condacolab\n", "# condacolab.install()\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", "import xarray as xr # used to manipulate data and open datasets\n", "import numpy as np # used for algebra/arrays\n", "import urllib.request # used to download data from the internet\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" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Figure settings\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "cellView": "form", "execution": {}, "executionInfo": { "elapsed": 418, "status": "ok", "timestamp": 1682124802617, "user": { "displayName": "Jenna Pearson", "userId": "05648130581702734913" }, "user_tz": 420 }, "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/ClimateMatchAcademy/course-content/main/cma.mplstyle\"\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Video 1: Radiative Equilibrium\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "cellView": "form", "execution": {}, "executionInfo": { "elapsed": 382, "status": "ok", "timestamp": 1682124802996, "user": { "displayName": "Jenna Pearson", "userId": "05648130581702734913" }, "user_tz": 420 }, "tags": [ "hide-input" ] }, "outputs": [], "source": [ "# @title Video 1: Radiative Equilibrium\n", "# Tech team will add code to format and display the video" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {} }, "outputs": [], "source": [ "# helper functions\n", "\n", "\n", "def pooch_load(filelocation=None, filename=None, processor=None):\n", " shared_location = \"/home/jovyan/shared/Data/tutorials/W1D4_Paleoclimate\" # 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" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "# **Section 1: Setting up the Radiative Equilibrium Model Using Climlab**" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "\n", "The energy balance model we used earlier today was *zero-dimensional*, yielding only the global mean surface temperature. We might ask, is it possible to construct a similar, *one-dimensional*, model for an *atmospheric column* to estimate the global mean temperature *profile* (i.e., including the height/$z$ dimension). Additionally, can we explicitly include the effects of different gases in this model, rather than just parametrizing their collective effects through a single parameter $\\tau$? **The answer is yes, we can!**\n", "\n", "This model is too complex to construct from scratch, as we did in the previous tutorials. Instead, we will use a model already available within the python package [climlab](https://climlab.readthedocs.io/en/latest/intro.html). \n", " \n", "The model we will first use is a radiative equilbrium model. **Radiative equilibrium models** consider different layers of the atmosphere. Each of these layers absorbs and emits radiation depending on its constituent gases, allowing the model to calculate the radiation budget for each layer as radiative energy is transferred between atmospheric layers, the Earth's surface, and space. **Radiative equilibrium** is reached when each layer gains energy at the same rate as it loses energy. In this tutorial you will analyze the temperature profile of this new model once it has reached equilibrium.\n", "\n", "To set up this model, we will need information about some of the mean properties of the atmosphere. We are going to download water vapor data from the Community Earth System Model, a global climate model that we will go into detail on in the next tutorial, to use a variable called [specific humidity](https://glossary.ametsoc.org/wiki/Specific_humidity). **Specific humidity** is the mass of water vapor per mass of a unit block of air. This is useful because water vapor is an important greenhouse gas." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {}, "executionInfo": { "elapsed": 121302, "status": "ok", "timestamp": 1682124999876, "user": { "displayName": "Jenna Pearson", "userId": "05648130581702734913" }, "user_tz": 420 } }, "outputs": [], "source": [ "filename_sq = \"cpl_1850_f19-Q-gw-only.cam.h0.nc\"\n", "url_sq = \"https://osf.io/c6q4j/download/\"\n", "\n", "ds = xr.open_dataset(\n", " pooch_load(filelocation=url_sq, filename=filename_sq)\n", ") # ds = dataset\n", "ds" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {} }, "outputs": [], "source": [ "# the specific humidity is stored in a variable called Q\n", "ds.Q" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {} }, "outputs": [], "source": [ "ds.time" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "however, we want an annual average profile:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {}, "executionInfo": { "elapsed": 5500, "status": "ok", "timestamp": 1680830700022, "user": { "displayName": "Abigail Bodner", "userId": "16617086768288510233" }, "user_tz": 240 } }, "outputs": [], "source": [ "# take global, annual average using a weighting (ds.gw) that is calculated based on the model grid - and is similar, but not identical, to a cosine(latitude) weighting\n", "\n", "weight_factor = ds.gw / ds.gw.mean(dim=\"lat\")\n", "Qglobal = (ds.Q * weight_factor).mean(dim=(\"lat\", \"lon\", \"time\"))\n", "# print specific humidity profile\n", "Qglobal" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "Now that we have a global mean water vapor profile, we can define a model that has the same vertical levels as this water vapor data." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {}, "executionInfo": { "elapsed": 148, "status": "ok", "timestamp": 1680831446236, "user": { "displayName": "Abigail Bodner", "userId": "16617086768288510233" }, "user_tz": 240 } }, "outputs": [], "source": [ "# 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", "mystate" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "To model the absorption and emission of different gases within each atmospheric layer, we use the **[Rapid Radiative Transfer Model](https://climlab.readthedocs.io/en/latest/api/climlab.radiation.RRTMG.html)**, which is contained within the `RRTMG` module. We must first initialize our model using the water vapor ." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {}, "executionInfo": { "elapsed": 3619, "status": "ok", "timestamp": 1680831453423, "user": { "displayName": "Abigail Bodner", "userId": "16617086768288510233" }, "user_tz": 240 } }, "outputs": [], "source": [ "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, # this the SURFACE shortwave albedo\n", " timestep=climlab.constants.seconds_per_day, # set the timestep to one day (measured in seconds)\n", ")\n", "radmodel" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "Let's explore this initial state. Here `Ts` is the initial global mean surface temperature, and `Tatm` is the initial global mean air temperature profile." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {}, "executionInfo": { "elapsed": 115, "status": "ok", "timestamp": 1680831456021, "user": { "displayName": "Abigail Bodner", "userId": "16617086768288510233" }, "user_tz": 240 } }, "outputs": [], "source": [ "radmodel.state" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "One of the perks of using this model is it's ability to incorporate the radiative effects of individual greenhouse gases in different parts of the radiation spectrum, rather than using a bulk reduction in transmission of outgoing longwave radiation (as in our previous models).\n", "\n", "Let's display 'absorber_vmr', which contains the **volume mixing ratio**'s of each gas used in the radiative transfer model (these are pre-defined; and do not include the water vapor we used as a model input above). The volume mixing ratio describes the fraction of molecules in the air that are a given gas. For example, $21\\%$ of air is oxygen and so it's volumn mixing ratio is 0.21." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {}, "executionInfo": { "elapsed": 158, "status": "ok", "timestamp": 1680831467961, "user": { "displayName": "Abigail Bodner", "userId": "16617086768288510233" }, "user_tz": 240 } }, "outputs": [], "source": [ "radmodel.absorber_vmr" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "To look at carbon dioxide (`CO2`) in a more familiar unit, parts per million (by volume), we can convert and print the new value." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {}, "executionInfo": { "elapsed": 125, "status": "ok", "timestamp": 1680831471172, "user": { "displayName": "Abigail Bodner", "userId": "16617086768288510233" }, "user_tz": 240 } }, "outputs": [], "source": [ "radmodel.absorber_vmr[\"CO2\"] * 1e6" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "We can also look at all the available diagnostics of our model:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {}, "executionInfo": { "elapsed": 287, "status": "ok", "timestamp": 1680831473662, "user": { "displayName": "Abigail Bodner", "userId": "16617086768288510233" }, "user_tz": 240 } }, "outputs": [], "source": [ "diag_ds = climlab.to_xarray(radmodel.diagnostics)\n", "diag_ds" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "For example to look at OLR," ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {}, "executionInfo": { "elapsed": 158, "status": "ok", "timestamp": 1680831477856, "user": { "displayName": "Abigail Bodner", "userId": "16617086768288510233" }, "user_tz": 240 } }, "outputs": [], "source": [ "radmodel.OLR" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "Note. the OLR is currently 0 as we have not ran the model forward in time, so it has not calculated any radiation components." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "## **Questions 1: Climate Connection**" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "1. Why do you think all gases, except ozone and water vapor, are represented by single values in the model?" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {} }, "outputs": [], "source": [ "# to_remove explanation\n", "\n", "\"\"\"\n", "1. The gases aside from ozone and water vapor are all assumed to be well mixed in the atmosphere. This means that we assume they have the same concentration anywhere you measure. However, we know from observations that ozone and water vapor are not well mixed in the atmosphere.\n", "\"\"\";" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "## **Coding Exercises 1**" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "1. On the same graph, plot the annual mean specific humidity profile and ozone profiles." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "execution": {} }, "source": [ "```python\n", "fig, ax = plt.subplots()\n", "# multiply Qglobal by 1000 to put in units of grams water vapor per kg of air\n", "_ = ...\n", "# multiply by 1E6 to get units of ppmv = parts per million by volume\n", "_ = ...\n", "\n", "# pressure decreases logarithmically with height in the atmosphere\n", "# invert the axis so the largest value of pressure is lowest\n", "ax.invert_yaxis()\n", "# set y axis to a log scale\n", "_ = ...\n", "\n", "ax.set_ylabel(\"Pressure (hPa)\")\n", "ax.set_xlabel(\"Specific humidity (g/kg)\")\n", "\n", "# turn on the grid lines\n", "_ = ...\n", "\n", "# turn on legend\n", "_ = ...\n", "\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {}, "executionInfo": { "elapsed": 2400, "status": "ok", "timestamp": 1680831485188, "user": { "displayName": "Abigail Bodner", "userId": "16617086768288510233" }, "user_tz": 240 } }, "outputs": [], "source": [ "# to_remove solution\n", "fig, ax = plt.subplots()\n", "# multiply Qglobal by 1000 to put in units of grams water vapor per kg of air\n", "_ = ax.plot(Qglobal * 1000.0, Qglobal.lev, label=\"Specific humidity (g/kg)\")\n", "# multiply by 1E6 to get units of ppmv = parts per million by volume\n", "_ = ax.plot(radmodel.absorber_vmr[\"O3\"] * 1e6, radmodel.lev, label=\"Ozone (ppmv)\")\n", "\n", "# pressure decreases logarithmically with height in the atmosphere\n", "# invert the axis so the largest value of pressure is lowest\n", "_ = ax.invert_yaxis()\n", "# set y axis to a log scale\n", "ax.set_yscale(\"log\")\n", "\n", "ax.set_ylabel(\"Pressure (hPa)\")\n", "ax.set_xlabel(\"Specific humidity (g/kg)\")\n", "\n", "# turn on the grid lines\n", "_ = ax.grid()\n", "\n", "# turn on legend\n", "_ = ax.legend()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "# **Section 2: Getting Data to Compare to the Model**" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "Before we run our model forward, we will download a reanalysis product from NCEP to get a sense of what the real global mean atmospheric temperature profile looks like. We will compare this profile to our model runs later." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {}, "executionInfo": { "elapsed": 979, "status": "ok", "timestamp": 1682125086037, "user": { "displayName": "Jenna Pearson", "userId": "05648130581702734913" }, "user_tz": 420 } }, "outputs": [], "source": [ "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", "# this is the long term monthly means (note only 12 time steps)\n", "ncep_air.air" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {}, "executionInfo": { "elapsed": 7, "status": "ok", "timestamp": 1680662820551, "user": { "displayName": "Jenna Pearson", "userId": "05648130581702734913" }, "user_tz": 420 } }, "outputs": [], "source": [ "# 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", "Tglobal = (ncep_air.air * weight).mean(dim=(\"lat\", \"lon\", \"time\"))\n", "Tglobal" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "Below we will define two helper funcitons to visualize the profiles output from our model with a *SkewT* plot. This is common way to plot atmospheric temperature in climate science, and the `metpy` package has a built in function to make this easier.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {} }, "outputs": [], "source": [ "# 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" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {} }, "outputs": [], "source": [ "# 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": "code", "execution_count": null, "metadata": { "execution": {}, "executionInfo": { "elapsed": 2544, "status": "ok", "timestamp": 1680662823964, "user": { "displayName": "Jenna Pearson", "userId": "05648130581702734913" }, "user_tz": 420 } }, "outputs": [], "source": [ "skew = make_skewT()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "SkewT (also known as SkewT-logP) plots are generally used for much [more complex reasons](https://www.weather.gov/source/zhu/ZHU_Training_Page/convective_parameters/skewt/skewtinfo.html) than we will use here. However, one of the benefits of this plot that we will utilize is the fact that pressure decreases approximately logarithmically with height. Thus, with a *logP* axis, we are showing information that is roughly linear in height, making the plots more intuitive. " ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "# **Section 3: Running the Radiative Equilibrium Model Forward in Time**" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "We can run this model over many time steps, just like the simple greenhouse model, but now we can examine the behavior of the temperature profile rather than just the surface temperature. \n", "\n", "There is no need to write out a function to step our model forward - `climlab` already has this feature. We will use this function to run our model to equilibrium (i.e., until OLR is balanced by ASR)." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {} }, "outputs": [], "source": [ "# take a single step forward to 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()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {}, "executionInfo": { "elapsed": 7, "status": "ok", "timestamp": 1680662825783, "user": { "displayName": "Jenna Pearson", "userId": "05648130581702734913" }, "user_tz": 420 } }, "outputs": [], "source": [ "# check the energy budget to make sure we are really at equilibrium\n", "radmodel.ASR - radmodel.OLR" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "Now let's can compare this to observations." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {}, "executionInfo": { "elapsed": 2330, "status": "ok", "timestamp": 1680662828107, "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\", fontsize=18);" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "## **Questions 3: Climate Connection**" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "1. The profile from our model does not match observations well. Can you think of one component we might be missing?\n", "2. What effect do you think the individual gases play in determining this profile and why?" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {} }, "outputs": [], "source": [ "# to_remove explanation\n", "\n", "\"\"\"\n", "1. One thing we are currently lacking is physical processes (aside from radiation) in our model.\n", "2. This is a hard question to answer! Luckily we can remove gases one at a time from our model to study their individual impact. Any ideas you have here can be tested with this model!\n", "\"\"\";" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "## **Coding Exercises 3**" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "1. Create a second model called 'Radiation (no H20)' that lacks water vapor. Then re-create the plot above, but add on this extra profile without water vapor." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "execution": {} }, "source": [ "```python\n", "# make an exact clone of our existing model\n", "radmodel_noH2O = climlab.process_like(radmodel)\n", "# change the name of our new model\n", "radmodel_noH2O.name = ...\n", "\n", "# set the water vapor profile to all zeros\n", "radmodel_noH2O.specific_humidity *= 0.0\n", "\n", "# run the model to equilibrium\n", "radmodel_noH2O.step_forward()\n", "while np.abs(radmodel_noH2O.ASR - radmodel_noH2O.OLR) > 0.01:\n", " radmodel_noH2O.step_forward()\n", "\n", "# create skewT plot\n", "skew = make_skewT()\n", "\n", "# add profiles for both models to plot\n", "for model in [...]:\n", " ...\n", "\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {}, "executionInfo": { "elapsed": 5291, "status": "ok", "timestamp": 1680662833394, "user": { "displayName": "Jenna Pearson", "userId": "05648130581702734913" }, "user_tz": 420 } }, "outputs": [], "source": [ "# to_remove solution\n", "\n", "# make an exact clone of our existing model\n", "radmodel_noH2O = climlab.process_like(radmodel)\n", "# change the name of our new model\n", "radmodel_noH2O.name = \"Radiation (no H2O)\"\n", "\n", "# set the water vapor profile to all zeros\n", "radmodel_noH2O.specific_humidity *= 0.0\n", "\n", "# run the model to equilibrium\n", "radmodel_noH2O.step_forward()\n", "while np.abs(radmodel_noH2O.ASR - radmodel_noH2O.OLR) > 0.01:\n", " radmodel_noH2O.step_forward()\n", "\n", "# create skewT plot\n", "skew = make_skewT()\n", "\n", "# add profiles for both models to plot\n", "for model in [radmodel, radmodel_noH2O]:\n", " add_profile(skew, model)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "# **Summary**\n", "In this tutorial, you've learned how to use the python package `climlab` to construct a one-dimensional radiative equilibrium model, and run it forward in time to predict the global mean atmospheric temperature profile. You've also visualized these results through SkewT plots." ] }, { "attachments": {}, "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)." ] } ], "metadata": { "colab": { "collapsed_sections": [], "include_colab_link": true, "name": "W1D5_Tutorial5", "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.10.12" } }, "nbformat": 4, "nbformat_minor": 4 }