From 5aaee37ce6682553ea8e6996133f3e62096146f6 Mon Sep 17 00:00:00 2001
From: "Tantet Alexis (M.)"
Date: Sat, 16 Jan 2021 21:15:17 +0100
Subject: [PATCH] add equilibrium temperature coding
---
book/equilibrium_climate_sensitivity.ipynb | 481 +++++++++++++--------
1 file changed, 293 insertions(+), 188 deletions(-)
diff --git a/book/equilibrium_climate_sensitivity.ipynb b/book/equilibrium_climate_sensitivity.ipynb
index 2b6990b..33e31f6 100644
--- a/book/equilibrium_climate_sensitivity.ipynb
+++ b/book/equilibrium_climate_sensitivity.ipynb
@@ -30,8 +30,17 @@
"- experiment changes in radiative-equilibrium conditions in an energy-balance model in response to carbon-dioxide (CO2) concentration changes,\n",
"- identify the main physical mechanisms associated to climate feedback loops,\n",
"- apply equilibrium climate sensitivity concepts to quantify the sensitivity of the climate system.\n",
- "\n",
- "\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
"## Taking the observed Earth energy budget as a reference\n",
"\n",
"Our starting point is the observed Earth energy budget.\n",
@@ -43,8 +52,17 @@
"\n",
"We can see from this figure that, even when globally averaged, the Earth energy budget involves a number of complex processes.\n",
"Our objective is to focus on the radiative processes and to relate them to the sensitivity of the climate to changes in CO2 concentrations.\n",
- "To do so, we build on Chapter 1 to design a zero-dimensional Earth-system model.\n",
- "\n",
+ "To do so, we build on Chapter 1 to design a zero-dimensional Earth-system model."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
"## Towards a zero-dimensional Earth-system model\n",
"\n",
"We focus on the radiative balance of the global Earth, ignoring the surface-atmosphere energy transfers associated with the water cycle (latent heating) and the contact of air masses with the surface (sensible heating).\n",
@@ -83,9 +101,17 @@
"> ***Question 1***\n",
"> - Identify the terms in the figure of the Earth energy budget above with the terms of the fully-absorbing EBM (Eq. 1).\n",
"> - Which terms in the figure are neglected in the fully-absorbing EBM?\n",
- "> - Does varying Greenhouse Gas (GHG) concentrations have an impact on the fully-absorbing EBM?\n",
- "\n",
- "\n",
+ "> - Does varying Greenhouse Gas (GHG) concentrations have an impact on the fully-absorbing EBM?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
"### For a partially-absorbing atmosphere\n",
"\n",
"We now develop a more general EBM.\n",
@@ -126,172 +152,16 @@
"> - What do the terms $\\alpha$ and $G$ represent in both EBMs?\n",
"\n",
"> ***Question 3***\n",
- "> - Give the formula for the radiative-equilibrium temperature $T_0$ for the partially-absorbing EBM (Eq. 3).\n",
- "> - Sketch the radiative-equilibrium temperature $T_0$ as a function of $G$ ranging from the case of an atmosphere which is fully transparent to terrestrial radiation to the case of an atmosphere which is fully absorbing terrestrial radiation, for fixed variables $\\alpha$ and $S$.\n",
- "> - Explain the dependence of the radiative-equilibrium temperature $T_0$ on $G$.\n",
- "\n",
- "\n",
- " - Feedback loop
\n",
- " - \n",
- " Cycles of variables along which a perturbation of one of these variables is propagated through the other variables all the way back to the first variable.\n",
- " A feedback loop is said to be positive (resp. negative) if it is amplifying (resp. damping) the initial perturbation.\n",
- " Example from ecology: a boom in prey population will mean more food for predators, which will increase predator numbers.\n",
- " This will then lead to over predation, and the prey population will again decline. The predator population will decline in response.\n",
- " This is a negative feedback.\n",
- "
\n",
- "

\n",
- "\n",
- "> ***Question 4***\n",
- "> - Based on what you have learned in Chapter 1, qualitatively describe the most important relationships between the prognostic variables $T$, $CO2$ and $\\phi$ and the diagnostic variables $Q$, $\\alpha$, $I$ and $G$ that should be represented in the partially-absorbing EBM (Eq. 3).\n",
- "> - Identify two major feedback loops and whether they are positive or negative.\n",
- "\n",
- "## Estimating the Equilibrium Climate Sensitivity (ECS)\n",
- "\n",
- "The IPCC (2013) gives the following definition of the ECS:\n",
- "\n",
- "\n",
- " - Equilibrium Climate Sensitivity
\n",
- " - The equilibrium change in global and annual mean surface air temperature after doubling the atmospheric concentration of CO2 relative to pre-industrial levels.
\n",
- "

\n",
- "\n",
- "The warming measured by the ECS results from a combination of the warming induced by the increase in CO2 concentrations all other conditions remaining the same, and the warming (resp. cooling) due to positive (resp. negative) feedbacks, as illustrated in the following figure.\n",
- "\n",
- "![ECS](https://upload.wikimedia.org/wikipedia/commons/thumb/2/2a/CS_diagram.svg/500px-CS_diagram.svg.png)\n",
- "\n",
- "Source: [Femkemilene. Creative Commons Attribution-Share Alike 4.0 International license](https://commons.wikimedia.org/wiki/File:CS_diagram.svg).\n",
- "\n",
- "Our objective is to estimate the ECS from the partially-absorbing EBM.\n",
- "\n",
- "### Implementing the partially-absorbing EBM\n",
- "\n",
- "The EBM is implemented in Python.\n",
- "The equations of the model are defined in the `BaseClimate` class in [simclimat/model.py](simclimat/model.py).\n",
- "The equation for the incoming radiation $Q$ (Eq. 2) is coded in the `get_power_in` method as\n",
- "```python\n",
- " power_in = (1. - albedo) * s0 / 4\n",
- "```\n",
- "and the equation for the outgoing radiation $I$ (Eq. 2) is coded in the `get_power_out` method as\n",
- "```python\n",
- " power_out = (1. - gh_frac) * self.param['sigma'] * state['temp']**4\n",
- "```\n",
- "where `state` is a dictionary storing the current values of the temperature (`'temp'`), CO2 concentration (`'co2'`) and latitudinal ice extent (`'lat_ice'`) of the system.\n",
- "\n",
- "The right-hand side of the prognostic equations for the temperature, the CO2 concentration and the ice extent are given by `field_temperature`, `field_co2` and `field_latitude_ice`, respectively.\n",
- "For instance, for the temperature,\n",
- "```python\n",
- " def field_temperature(self, state, t=None):\n",
- " \"\"\"Get value of the component of the vector field associated with\n",
- " the temperature at the current state.\"\"\"\n",
- " # Solar power absorbed by the Earth\n",
- " power_in = self.get_power_in(state)\n",
- " \n",
- " # Solar power radiated out by the Earth\n",
- " power_out = self.get_power_out(state)\n",
- " \n",
- " val = (power_in - power_out) / self.param['tau_re']\n",
- " \n",
- " return val\n",
- "```\n",
- "\n",
- "From the code, it may look like that the variables entering the equations are constant parameters.\n",
- "However, apart from the actual parameters which are stored in the `self.param` dictionary, all the variables (`power_in`, `power_out`, `albedo`, `gh_frac`, etc.) depend on the current value of the state variables.\n",
- "As discussed below the latter are updated at every iteration of the model.\n",
- "\n",
- "### Understanding how to use the partially-absorbing EBM to compute the ECS\n",
- "\n",
- "In the following, we need the following definition of a stationary solution:\n",
- "\n",
- "\n",
- " - Stationary solution
\n",
- " - \n",
- " A solution of the model for which the prognostic variables do not evolve in time.\n",
- "
\n",
- "

\n",
- "\n",
- "In the case of the partially-absorbing EBM (Eq. 3), this means that,\n",
- " \n",
- "\\begin{equation}\n",
- " \\begin{aligned}\n",
- " \\frac{d T}{d t}(t) &= 0\\\\\n",
- " \\frac{d CO2}{d t}(t) &= 0\\\\\n",
- " \\frac{d \\phi}{d t}(t) &= 0.\n",
- " \\end{aligned}\n",
- "\\end{equation}\n",
- "\n",
- "The partially-absorbing EBM can be run in two modes:\n",
- "\n",
- "- **Numerical integration mode:** the prognostic equations are numerically integrated from some initial state forward in time to give the transient evolution of the model during a given period.\n",
- "The governing equations being continuous in time, they need to be discretized to be integrated numerically.\n",
- "For that purpose, we use the Euler numerical scheme for some time step of integration $\\delta t$, chosen here as one year.\n",
- "For instance, the temperature for the year $t_n$ is obtained from the previous year $t_{n - 1}$ according to \n",
- " \\begin{align} \n",
- " T(t_n) = T(t_{n-1}) + \\delta t (Q(t) - I(t)) / \\tau_{\\mathrm{RE}}. \n",
- " \\end{align}\n",
- " This is illustrated in the following figure.\n",
- "\n",
- " ![Euler numerical integration](https://upload.wikimedia.org/wikipedia/commons/thumb/1/10/Euler_method.svg/200px-Euler_method.svg.png)\n",
- "\n",
- " Source: [Public Domain](https://commons.wikimedia.org/wiki/File:Euler_method.svg).\n",
- "\n",
- " This scheme is implemented in the `Euler` class in [simclimat/integration.py](simclimat/integration.py).\n",
- "A single iteration is obtained by calling the `iterate` method given by\n",
- "```python\n",
- " def iterate(self, state, t=None):\n",
- " \"\"\" Integrate the model one time step forward\n",
- " with a Euler scheme. \"\"\"\n",
- " # Evaluate the vector field at the current state\n",
- " vec = self.field(state, t)\n",
- " \n",
- " # Integrate the model one step forward with a Euler scheme\n",
- " # Index in case there are some constant variables in the state\n",
- " state[vec.keys()] += vec * self.dt\n",
- "```\n",
- "\n",
- "- **Numerical continuation mode:** directly solve for the stationary solutions of the model as some variable or parameter, the continuation variable, is changed. This is done by a succession of correction and prediction steps (see below).\n",
- "If this solution is (globally) stable, long integrations initialized in its neighborhood eventually converge to it.\n",
- "This integration process is, however, generally much slower than obtaining the stationary solution by continuation and does not work if this solution is unstable.\n",
- "The stationary solution is instead found by the repetition of a two-step process:\n",
- "\n",
- " - *Correction step*: the zeros of the right-hand side of the system of prognostic equations (Eq. 5) is solved for, e.g. by the iterative Newton method.\n",
- " - *Prediction step*: a prediction of the new value of the stationary solution for a new value of the continuation variable is made using the derivative of the right-hand side of the prognostic equations with respect to the continuation variable (assuming that small changes in the continuation variable lead to commensurate changes in the stationary solution).\n",
- " \n",
- " This two-step continuation process is repeated to get a graph of the stationary solution as a function of the continuation variable as illustrated below.\n",
- " It is implemented in the `ContinuatorFixedPoint` class in [simclimat/continuation.py](simclimat/continuation.py)\n",
- " \n",
- " ![Numerical continuation](https://upload.wikimedia.org/wikipedia/commons/a/a7/NaturalParameter.gif)\n",
- " \n",
- " Source: [Michael E Henderson. Free](https://commons.wikimedia.org/wiki/File:NaturalParameter.gif).\n",
- "\n",
- "(For the purpose of this course, it is not needed to know more about these numerical methods.) \n",
- "\n",
- "> ***Question 5***\n",
- "> - In which mode and how would you use the partially-absorbing EBM (Eq. 3) to compute the ECS, integration or continuation?\n",
- "> - Give the explicit formula that you would apply to compute the ECS according to its definition and assuming that the pre-industrial level is set to the year 1750 with a CO2 concentration of 280 ppm.\n",
- "\n",
- "### Analysing the solutions of the partially-absorbing EBM\n",
- "\n",
- "The following code implements a numerical application of the EBM to compute the ECS according to the correct reply to ***Question 5***.\n",
- "What matters here is not the code itself but how to access to the model results for analysis:\n",
- "- the results are represented below by a plot and a table giving the corresponding data,\n",
- "- different variables can be represented by clicking on the radio buttons below,\n",
- "- two physical processes can be activated or deactivated by clicking on the check-boxes below, and\n",
- "- the resulting ECS is also given in the bottom text-box below.\n",
- "\n",
- "Before that, the following code block must be run at least once by clicking inside it and pressing `Shift-Enter`."
+ "> - Derive the formula for the radiative-equilibrium temperature $T_0$ for the partially-absorbing EBM (Eq. 3).\n",
+ "> - Code this formula to define the `equilibrium_temperature` variable inside the `get_equilibrium_temperature` function in the code cell below.\n",
+ "> - Run the code cell to plot the radiative-equilibrium temperature $T_0$ as a function of $\\alpha$ and depending on $G$.\n",
+ "> - Explain the dependence of the radiative-equilibrium temperature $T_0$ on $G$."
]
},
{
"cell_type": "code",
"execution_count": 1,
- "metadata": {
- "code_folding": [],
- "slideshow": {
- "slide_type": "slide"
- },
- "tags": [
- "hide-input"
- ]
- },
+ "metadata": {},
"outputs": [
{
"data": {
@@ -1693,6 +1563,257 @@
"metadata": {},
"output_type": "display_data"
},
+ {
+ "ename": "NameError",
+ "evalue": "name 'np' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 30\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 31\u001b[0m \u001b[0;31m# Show interactive plot\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 32\u001b[0;31m \u001b[0mhvp\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mpn\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0minteract\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mget_equilibrium_temperature\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 33\u001b[0m \u001b[0mhvp\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32m~/.conda/envs/default/lib/python3.8/site-packages/panel/interact.py\u001b[0m in \u001b[0;36m__call__\u001b[0;34m(self, _InteractFactory__interact_f, **kwargs)\u001b[0m\n\u001b[1;32m 487\u001b[0m \u001b[0;31m# def f(*args, **kwargs):\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 488\u001b[0m \u001b[0;31m# ...\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 489\u001b[0;31m \u001b[0mw\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwidget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 490\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 491\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwidget\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mw\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32m~/.conda/envs/default/lib/python3.8/site-packages/panel/interact.py\u001b[0m in \u001b[0;36mwidget\u001b[0;34m(self, f)\u001b[0m\n\u001b[1;32m 410\u001b[0m \u001b[0mThe\u001b[0m \u001b[0mfunction\u001b[0m \u001b[0mto\u001b[0m \u001b[0mwhich\u001b[0m \u001b[0mthe\u001b[0m \u001b[0minteractive\u001b[0m \u001b[0mwidgets\u001b[0m \u001b[0mare\u001b[0m \u001b[0mtied\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 411\u001b[0m \"\"\"\n\u001b[0;32m--> 412\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcls\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopts\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 413\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 414\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m__call__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m__interact_f\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32m~/.conda/envs/default/lib/python3.8/site-packages/panel/interact.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, object, params, **kwargs)\u001b[0m\n\u001b[1;32m 151\u001b[0m \u001b[0mwidgets\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'manual'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mButton\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmanual_name\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 152\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_widgets\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mOrderedDict\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mwidgets\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 153\u001b[0;31m \u001b[0mpane\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mobject\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m**\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 154\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpane\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mViewable\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 155\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_pane\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mpane\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36mget_equilibrium_temperature\u001b[0;34m(G)\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0;31m# Set array of alpha values from 0 to 1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 18\u001b[0;31m \u001b[0malpha\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0marange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0.01\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 19\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[0;31m# TODO: replace 273 by the formula of the equilibrium temperature in K\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'np' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "# Data analysis and manipulation tools\n",
+ "import numpy as np\n",
+ "import pandas as pd\n",
+ "\n",
+ "# Imports for plotting\n",
+ "import hvplot.pandas\n",
+ "import panel as pn\n",
+ "import panel.widgets as pnw\n",
+ "\n",
+ "def get_equilibrium_temperature(G=0.25):\n",
+ " '''Get equilibrium temperature as a function of G.'''\n",
+ " # Set solar constant (W/m2)\n",
+ " solar_constant = 1370\n",
+ " \n",
+ " # Set Stefan-Boltzmann constant (Wm-2K-4)\n",
+ " sigma = 5.67e-8\n",
+ " \n",
+ " # Set array of alpha values from 0 to 1\n",
+ " alpha = np.arange(0, 1, 0.01)\n",
+ " \n",
+ " # TODO: replace 273 by the formula of the equilibrium temperature in K\n",
+ " equilibrium_temperature = 273\n",
+ " \n",
+ " # Make data frame indexed by alpha\n",
+ " df = pd.DataFrame(equilibrium_temperature, index=alpha,\n",
+ " columns=['Equilibrium Temperature'])\n",
+ " df.index.name = 'alpha'\n",
+ " \n",
+ " # Return plot\n",
+ " return df.hvplot(ylim=[220, 320]) \n",
+ "\n",
+ "# Show interactive plot\n",
+ "hvp = pn.interact(get_equilibrium_temperature)\n",
+ "hvp"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "\n",
+ " - Feedback loop
\n",
+ " - \n",
+ " Cycles of variables along which a perturbation of one of these variables is propagated through the other variables all the way back to the first variable.\n",
+ " A feedback loop is said to be positive (resp. negative) if it is amplifying (resp. damping) the initial perturbation.\n",
+ " Example from ecology: a boom in prey population will mean more food for predators, which will increase predator numbers.\n",
+ " This will then lead to over predation, and the prey population will again decline. The predator population will decline in response.\n",
+ " This is a negative feedback.\n",
+ "
\n",
+ "

\n",
+ "\n",
+ "> ***Question 4***\n",
+ "> - Based on what you have learned in Chapter 1, qualitatively describe the most important relationships between the prognostic variables $T$, $CO2$ and $\\phi$ and the diagnostic variables $Q$, $\\alpha$, $I$ and $G$ that should be represented in the partially-absorbing EBM (Eq. 3).\n",
+ "> - Identify two major feedback loops and whether they are positive or negative."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "## Estimating the Equilibrium Climate Sensitivity (ECS)\n",
+ "\n",
+ "The IPCC (2013) gives the following definition of the ECS:\n",
+ "\n",
+ "\n",
+ " - Equilibrium Climate Sensitivity
\n",
+ " - The equilibrium change in global and annual mean surface air temperature after doubling the atmospheric concentration of CO2 relative to pre-industrial levels.
\n",
+ "

\n",
+ "\n",
+ "The warming measured by the ECS results from a combination of the warming induced by the increase in CO2 concentrations all other conditions remaining the same, and the warming (resp. cooling) due to positive (resp. negative) feedbacks, as illustrated in the following figure.\n",
+ "\n",
+ "![ECS](https://upload.wikimedia.org/wikipedia/commons/thumb/2/2a/CS_diagram.svg/500px-CS_diagram.svg.png)\n",
+ "\n",
+ "Source: [Femkemilene. Creative Commons Attribution-Share Alike 4.0 International license](https://commons.wikimedia.org/wiki/File:CS_diagram.svg).\n",
+ "\n",
+ "Our objective is to estimate the ECS from the partially-absorbing EBM.\n",
+ "\n",
+ "### Implementing the partially-absorbing EBM\n",
+ "\n",
+ "The EBM is implemented in Python.\n",
+ "The equations of the model are defined in the `BaseClimate` class in [simclimat/model.py](simclimat/model.py).\n",
+ "The equation for the incoming radiation $Q$ (Eq. 2) is coded in the `get_power_in` method as\n",
+ "```python\n",
+ " power_in = (1. - albedo) * s0 / 4\n",
+ "```\n",
+ "and the equation for the outgoing radiation $I$ (Eq. 2) is coded in the `get_power_out` method as\n",
+ "```python\n",
+ " power_out = (1. - gh_frac) * self.param['sigma'] * state['temp']**4\n",
+ "```\n",
+ "where `state` is a dictionary storing the current values of the temperature (`'temp'`), CO2 concentration (`'co2'`) and latitudinal ice extent (`'lat_ice'`) of the system.\n",
+ "\n",
+ "The right-hand side of the prognostic equations for the temperature, the CO2 concentration and the ice extent are given by `field_temperature`, `field_co2` and `field_latitude_ice`, respectively.\n",
+ "For instance, for the temperature,\n",
+ "```python\n",
+ " def field_temperature(self, state, t=None):\n",
+ " \"\"\"Get value of the component of the vector field associated with\n",
+ " the temperature at the current state.\"\"\"\n",
+ " # Solar power absorbed by the Earth\n",
+ " power_in = self.get_power_in(state)\n",
+ " \n",
+ " # Solar power radiated out by the Earth\n",
+ " power_out = self.get_power_out(state)\n",
+ " \n",
+ " val = (power_in - power_out) / self.param['tau_re']\n",
+ " \n",
+ " return val\n",
+ "```\n",
+ "\n",
+ "From the code, it may look like that the variables entering the equations are constant parameters.\n",
+ "However, apart from the actual parameters which are stored in the `self.param` dictionary, all the variables (`power_in`, `power_out`, `albedo`, `gh_frac`, etc.) depend on the current value of the state variables.\n",
+ "As discussed below the latter are updated at every iteration of the model."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "### Understanding how to use the partially-absorbing EBM to compute the ECS\n",
+ "\n",
+ "In the following, we need the following definition of a stationary solution:\n",
+ "\n",
+ "\n",
+ " - Stationary solution
\n",
+ " - \n",
+ " A solution of the model for which the prognostic variables do not evolve in time.\n",
+ "
\n",
+ "

\n",
+ "\n",
+ "In the case of the partially-absorbing EBM (Eq. 3), this means that,\n",
+ " \n",
+ "\\begin{equation}\n",
+ " \\begin{aligned}\n",
+ " \\frac{d T}{d t}(t) &= 0\\\\\n",
+ " \\frac{d CO2}{d t}(t) &= 0\\\\\n",
+ " \\frac{d \\phi}{d t}(t) &= 0.\n",
+ " \\end{aligned}\n",
+ "\\end{equation}\n",
+ "\n",
+ "The partially-absorbing EBM can be run in two modes:\n",
+ "\n",
+ "- **Numerical integration mode:** the prognostic equations are numerically integrated from some initial state forward in time to give the transient evolution of the model during a given period.\n",
+ "The governing equations being continuous in time, they need to be discretized to be integrated numerically.\n",
+ "For that purpose, we use the Euler numerical scheme for some time step of integration $\\delta t$, chosen here as one year.\n",
+ "For instance, the temperature for the year $t_n$ is obtained from the previous year $t_{n - 1}$ according to \n",
+ " \\begin{align} \n",
+ " T(t_n) = T(t_{n-1}) + \\delta t (Q(t) - I(t)) / \\tau_{\\mathrm{RE}}. \n",
+ " \\end{align}\n",
+ " This is illustrated in the following figure.\n",
+ "\n",
+ " ![Euler numerical integration](https://upload.wikimedia.org/wikipedia/commons/thumb/1/10/Euler_method.svg/200px-Euler_method.svg.png)\n",
+ "\n",
+ " Source: [Public Domain](https://commons.wikimedia.org/wiki/File:Euler_method.svg).\n",
+ "\n",
+ " This scheme is implemented in the `Euler` class in [simclimat/integration.py](simclimat/integration.py).\n",
+ "A single iteration is obtained by calling the `iterate` method given by\n",
+ "```python\n",
+ " def iterate(self, state, t=None):\n",
+ " \"\"\" Integrate the model one time step forward\n",
+ " with a Euler scheme. \"\"\"\n",
+ " # Evaluate the vector field at the current state\n",
+ " vec = self.field(state, t)\n",
+ " \n",
+ " # Integrate the model one step forward with a Euler scheme\n",
+ " # Index in case there are some constant variables in the state\n",
+ " state[vec.keys()] += vec * self.dt\n",
+ "```\n",
+ "\n",
+ "- **Numerical continuation mode:** directly solve for the stationary solutions of the model as some variable or parameter, the continuation variable, is changed. This is done by a succession of correction and prediction steps (see below).\n",
+ "If this solution is (globally) stable, long integrations initialized in its neighborhood eventually converge to it.\n",
+ "This integration process is, however, generally much slower than obtaining the stationary solution by continuation and does not work if this solution is unstable.\n",
+ "The stationary solution is instead found by the repetition of a two-step process:\n",
+ "\n",
+ " - *Correction step*: the zeros of the right-hand side of the system of prognostic equations (Eq. 5) is solved for, e.g. by the iterative Newton method.\n",
+ " - *Prediction step*: a prediction of the new value of the stationary solution for a new value of the continuation variable is made using the derivative of the right-hand side of the prognostic equations with respect to the continuation variable (assuming that small changes in the continuation variable lead to commensurate changes in the stationary solution).\n",
+ " \n",
+ " This two-step continuation process is repeated to get a graph of the stationary solution as a function of the continuation variable as illustrated below.\n",
+ " It is implemented in the `ContinuatorFixedPoint` class in [simclimat/continuation.py](simclimat/continuation.py)\n",
+ " \n",
+ " ![Numerical continuation](https://upload.wikimedia.org/wikipedia/commons/a/a7/NaturalParameter.gif)\n",
+ " \n",
+ " Source: [Michael E Henderson. Free](https://commons.wikimedia.org/wiki/File:NaturalParameter.gif).\n",
+ "\n",
+ "(For the purpose of this course, it is not needed to know more about these numerical methods.) \n",
+ "\n",
+ "> ***Question 5***\n",
+ "> - In which mode and how would you use the partially-absorbing EBM (Eq. 3) to compute the ECS, integration or continuation?\n",
+ "> - Give the explicit formula that you would apply to compute the ECS according to its definition and assuming that the pre-industrial level is set to the year 1750 with a CO2 concentration of 280 ppm."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "### Analysing the solutions of the partially-absorbing EBM\n",
+ "\n",
+ "The following code implements a numerical application of the EBM to compute the ECS according to the correct reply to ***Question 5***.\n",
+ "What matters here is not the code itself but how to access to the model results for analysis:\n",
+ "- the results are represented below by a plot and a table giving the corresponding data,\n",
+ "- different variables can be represented by clicking on the radio buttons below,\n",
+ "- two physical processes can be activated or deactivated by clicking on the check-boxes below, and\n",
+ "- the resulting ECS is also given in the bottom text-box below.\n",
+ "\n",
+ "Before that, the following code block must be run at least once by clicking inside it and pressing `Shift-Enter`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "code_folding": [],
+ "slideshow": {
+ "slide_type": "slide"
+ },
+ "tags": [
+ "hide-input"
+ ]
+ },
+ "outputs": [
{
"name": "stdout",
"output_type": "stream",
@@ -1721,12 +1842,12 @@
"\n",
"\n",
"\n",
- " \n",
+ " \n",
"\n",
"