{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Simple tools for exploring exponential (geometric) CO₂ emission pathways\n",
"\n",
"## About this Notebook\n",
"\n",
"**Author:** [Barry McMullin](http://www.eeng.dcu.ie/~mcmullin)\n",
"\n",
"**Last updated:** 2nd December 2017\n",
"\n",
"A data product of the [IE-NETs research project](http://ienets.eeng.dcu.ie/), supported by the [Irish Environmental Projection Agency (EPA)](http://epa.ie/) Research Programme 2014-2020 (grant number 2016-CCRP-MS.36).\n",
"\n",
"## Motivation\n",
"\n",
"This notebook provides some very basic tools for modelling \"exponential mitigation pathways\" for greenhouse gases (GHGs).\n",
"\n",
"\"Exponential mitigation\" is a plausible \"default\" GHG emissions mitigation pathway: it is characterised by a constant year-on-year fractional reduction of annual emissions, typically expressed as the percentage reduction (here denoted $m$, and with a negative value indicating exponential _decline_). It is plausible because earlier emissions reductions, relative to a large base, are likely to be easier to achieve than later reductions relative to an already much contracted base (the \"low hanging fruit\" concept). So, as a first, crude, approximation, constant fractional reduction corresponds to something like \"constant mitigation effort\".\n",
"\n",
"Exponentially declining pathways are also characterised by having finite cumulative emissions, or \"quota\" (\"area under the curve\") when extended to infinite time; and for any given quota, relative to a given starting emissions level, any alternative pathway (having varying mitigation rate) would, at some point, require a mitigation rate _higher_ than the constant rate of the exponential pathway. That is, for given quota, and starting emissions level, the (unique) corresponding exponential pathway represents the pathway with the \"least maximum\" mitigation rate (in fact, constant mitigation rate). This quota consideration is of particular relevance to CO₂: as a very long lived gas, its warming effect is best understood by looking not at the emissions rate in any particular year, but the accumulation in time; and, to stabilize climate, it must indeed fall to (nett) zero (at least), which is not necessarily true of shorter-lived GHGs.\n",
"\n",
"Exponentially growing pathways are also a common modelling default: in the context of policies promoting some target level of economic growth, and in the absence of stringent decoupling of emissions from such growth, then the default emissions pathway would also be growth at a (fixed) target level, or exponential growth. Such pathways are characterised by the same mathematical form, but now $m$ is positive rather than negative, and the cumulative emissions are now constrained by any finite limit.\n",
"\n",
"As a special case, $m=0$% represents constant or \"flat-lined\" emissions.\n",
"\n",
"## Mathematical formulation\n",
"\n",
"The discussion so far has been in terms of \"expoential\" functions which, in a technical mathematical sense would be functions of a continuous independent variable (time). In practice, GHG inventory reporting is in terms of a discrete time variable (normally _annual_ emissions). Accordingly, the formal mathematical treatment is not an exponential function of a continuous variable but rather takes the form of a _geometric series_ where each succeeding element of the series is in a fixed proportion to the previous element.\n",
"\n",
"While the motivation above is in terms of GHG emissions pathways, the rest of this notebook deals with essentially abstract properties of mathematical functions, not intrinsically linked to that motivation.\n",
"\n",
"A geometric series is characterised in general as:\n",
"\n",
"$$ x(k) = x_0 r^k $$\n",
"\n",
"where: $k$ represents the time (year) relative to some arbitrary base year ($0$); $x_0$ is the emissions level in year $0$; $r$ is the (fixed) geometric ratio between the emissions in any given year and the previous year. Mitigation is represented by $r<1$, and growth by $r>1$ (and flatlining by $r=1$). The year on year fractional _change_, introduced previously, is given by $m = (r-1)$.\n",
"\n",
"The cumulative emissions over any given number of steps (years), $n$, is given by the sum of this series:\n",
"\n",
"$$Q(n) = \\sum_{k=0}^{k=(n-1)} x(k) = x_0 \\left (\\frac{1-r^n}{1-r} \\right )$$\n",
"\n",
"Provided $r<1$ (i.e., $m<0$) this converges to a finite limit as $n \\rightarrow \\infty$:\n",
"\n",
"$$Q_\\infty = \\frac{x_0}{1-r}$$\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Case 1: Given $Q_\\infty$, $x_0$ find $m$\n",
"\n",
"This is the most basic case of finding the exponential mitigation pathway corresponding to a finite cumulative quota. Such a quota would typically arise from a global temperature limit, and, if looking at a nation state or other sub-global agent, some allocation of that quota to the mitigation agent in question. That is, given a \"current\" emissions rate ($x_0$ in the base year, $k=0$) what mitigation rate ($m$) is required so that the quota ($Q_\\infty$) is respected?\n",
"\n",
"$$Q_\\infty = \\frac{x_0}{1-r}$$\n",
"$$Q_\\infty(1-r) = x_0$$\n",
"$$Q_\\infty - r Q_\\infty = x_0$$\n",
"$$r Q_\\infty = Q_\\infty - x_0$$\n",
"$$r = \\frac{Q_\\infty - x_0}{Q_\\infty}$$\n",
"$$r = 1 - \\left ( \\frac{x_0}{Q_\\infty} \\right )$$\n",
"\n",
"and:\n",
"$$m = (r-1) = - \\frac{x_0}{Q_\\infty} $$\n",
"\n",
"Note that the convention here is that the year $0$ emissions are _included_ in the quota. (If one is working from an historical emissions inventory for, say, the year _before_ the quota is due to begin, then just subtract that amount from the notional quota.)\n"
]
},
{
"cell_type": "code",
"execution_count": 69,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"from ipywidgets import widgets\n",
"from IPython.display import display"
]
},
{
"cell_type": "code",
"execution_count": 80,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"x0_widget = widgets.FloatText(\n",
" value=40.0,\n",
" description='x0:',\n",
" disabled=False)\n",
"Q_widget = widgets.FloatText(\n",
" value=800.0,\n",
" description='Q:',\n",
" disabled=False)"
]
},
{
"cell_type": "code",
"execution_count": 83,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"x0 = 50.000\n",
"Q = 700.00%\n",
"r = 0.929\n",
"m = -7.14%\n"
]
}
],
"source": [
"# Fill in desired input values here and then run:\n",
"\n",
"#x0 = 40.0\n",
"display(x0_widget)\n",
"x0 = x0_widget.value\n",
"display(Q_widget)\n",
"Q = Q_widget.value\n",
"\n",
"# Calculate:\n",
"m = -(x0/Q)\n",
"r = m + 1.0 \n",
"\n",
"print \"x0 = %5.3f\" % x0\n",
"print \"Q = %5.2f%%\" % Q\n",
"print \"r = %5.3f\" % r\n",
"print \"m = %5.2f%%\" % (m*100.0)\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"## Case 2: Given $x_0$, $m$, $Q$ find $n$\n",
"\n",
"In this case we suppose we have some given pathway (starting level, $x_0$, rate parameter $m$) and some finite quota ($Q$), and we ask for the number of years ($n$) when that quota would be exhausted. The pathway could correspond to growth, flatlining or mitigation respectively, just depending on the value of $m$. We do assume that $n$ is finite; that is, either $m \\ge 0$ (flatlining or growth) or if $m < 0$ (mitigation), we have $Q < Q_\\infty$.\n",
"\n",
"$$Q = x_0 \\left (\\frac{1-r^n}{1-r} \\right )$$\n",
"$$(1-r) Q = x_0 (1-r^n)$$\n",
"$$(1-r) Q = x_0 - x_0 r^n$$\n",
"$$x_0r^n = x_0 - (1-r) Q$$\n",
"$$r^n = \\frac{x_0 - (1-r) Q}{x_0}$$\n",
"$$r^n = 1 - \\frac{(1-r) Q}{x_0}$$\n",
"$$n \\log(r) = \\log \\left( 1 - \\frac{(1-r) Q}{x_0} \\right)$$\n",
"$$n = \\frac{\\log \\left( 1 - \\frac{(1-r) Q}{x_0} \\right)}{\\log(r)}$$\n",
"\n",
"Note that $n$ may, in general, be fractional, indicating that the given quota will be exhausted at a point within the specified \"final\" year.\n",
"\n",
"Note that this formula does not work for the flatlining case, $m = 0, r=1$ (would throw a divide-by-zero error). In that case we use simply:\n",
"\n",
"$$ Q = n x_0$$\n",
"$$ n = Q / x_0 $$\n"
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"n = 11.527\n"
]
}
],
"source": [
"import math\n",
"\n",
"# Fill in desired input values here and then run:\n",
"\n",
"x0 = 40.0\n",
"Q = 800.0\n",
"m = 0.1\n",
"\n",
"# Calculate:\n",
"if (m == 0.0):\n",
" n = Q / x0\n",
"else: \n",
" r = m + 1.0\n",
" n = math.log(1.0 - (((1.0-r)*Q)/x0))/math.log(r)\n",
"\n",
"print \"n = %5.3f\" % n\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"## Case 3: Given $n$,$Q$, $x_0$ find $m$\n",
"\n",
"In this case we suppose we have some given quota for some fixed number of years from the (arbitrary) basis year, $Q(n)$, and we want to know what exponential pathway, over that same number of years, would have the same quota; that is, regardless of the actual pathway form, find the unique exponential pathway which, over that period, would be \"equivalent\" _from the cumulative point of view_. Note that, in this case, $m$ could turn out to be positive, negative or zero: that is, the \"equivalent\" exponential pathway could correspond to growth, flatlining or mitigation respectively, just depending on what parameters are given.\n",
"\n",
"$$Q = x_0 \\left (\\frac{1-r^n}{1-r} \\right )$$\n",
"$$(1-r)Q = x_0 (1-r^n)$$\n",
"$$Q-rQ = x_0 - x_0 r^n$$\n",
"$$x_0 r^n - Q r + (Q - x_0) = 0$$\n",
"\n",
"So the required $r$ is the root of this degree $n$ polynomial. Unfortunately we don't have a closed form solution for this, so must rely on a numerical method ([numpy.roots()](https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.roots.html)).\n",
"\n",
"Note that $r=1$ is always a root of this equation; but that does not indicate a flatline pathway solution. Rather it is an artefact of the original equation being undefined for $r=1$. Thus we need to check explicitly first for the $r=1$ solution (i.e., $Q = n x_0$); and only once this is excluded do we proceed to solve the polynomial. Note also that, in general, the equation may have negative or complex roots; which again, are not meaningful in our target application context, and should be excluded.\n"
]
},
{
"cell_type": "code",
"execution_count": 49,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"r = 1.087\n",
"m = 8.73%\n"
]
}
],
"source": [
"import numpy as np\n",
"\n",
"# Fill in desired input values here and then run:\n",
"\n",
"n = 10 # Must be integer!\n",
"Q = 600.0\n",
"x0 = 40.0\n",
"\n",
"# Caclulate\n",
"\n",
"# Check for r = 1:\n",
"\n",
"if (Q == n * x0):\n",
" r = 1.0\n",
"else:\n",
"\n",
" # Polynomial: x0 * r^n - Q * r + (Q-x0) = 0\n",
" poly = np.zeros(n+1)\n",
" poly[0] = x0\n",
" poly[n-1] = -Q\n",
" poly[n] = Q - x0\n",
"\n",
" # DEBUG\n",
" # print poly\n",
"\n",
" roots = np.roots(poly)\n",
" k = 0\n",
" while (k < n):\n",
" root = roots[k]\n",
" if (np.abs(root - 1.0) > 1e-10) and (root > 0.0) and np.isreal(root):\n",
" r = root.real\n",
" k = k+1\n",
"\n",
"print \"r = %5.3f\" % r\n",
"m = r - 1.0\n",
"print \"m = %5.2f%%\" % (m*100.0)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## TODO\n",
"\n",
"For case 3, I suspect the computation would be simpler if we just used a general (real valued) root finder constrained (say) to the range (0, 2.0]? Would at least avoid having to explicitly exclude the negative and complex roots."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"language": "python",
"name": "python2"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 0
}