Source code for tonyear.ghgforcing

# Module developed from:
# https://github.com/gschivley/ghgforcing/blob/master/ghgforcing/ghgforcing.py
# The MIT License (MIT)

# Copyright (c) 2016 Greg Schivley

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

from typing import Tuple

import numpy as np
import pandas as pd
from scipy.stats import multivariate_normal


[docs] def joos_2013(t_horizon: int, **kwargs) -> np.ndarray: """Returns the IRF for CO2 using parameter values from IPCC AR5/Joos et al (2013) Keyword arguments are parameter values. Parameters ---------- t_horizon : int Length of the time horizon (years) Returns ------- IRF : np.ndarray IRF curve in the form of an 1D array """ a0 = kwargs.get("a0", 0.2173) a1 = kwargs.get("a1", 0.224) a2 = kwargs.get("a2", 0.2824) a3 = kwargs.get("a3", 0.2763) tau1 = kwargs.get("tau1", 394.4) tau2 = kwargs.get("tau2", 36.54) tau3 = kwargs.get("tau3", 4.304) t = np.arange(t_horizon) IRF = a0 + a1 * np.exp(-t / tau1) + a2 * np.exp(-t / tau2) + a3 * np.exp(-t / tau3) return IRF
[docs] def joos_2013_monte_carlo( runs: int = 100, t_horizon: int = 1001, **kwargs ) -> Tuple[pd.DataFrame, np.ndarray]: """Runs a monte carlo simulation for the Joos_2013 baseline IRF curve. This function uses uncertainty parameters for the Joos_2013 curve calculated by Olivie and Peters (2013): https://esd.copernicus.org/articles/4/267/2013/ Parameters ---------- runs : int Number of runs for Monte Carlo simulation. Must be >1. t_horizon : int Length of the time horizon over which baseline curve is calculated (years) Returns ------- summary : pd.DataFrame Dataframe with 'mean', '+sigma', and '-sigma' columns summarizing results of Monte Carlo simulation. results : np.ndarray Results from all Monte Carlo runs. """ if runs <= 1: raise ValueError("number of runs must be >1") results = np.zeros((t_horizon, runs)) # Monte Carlo simulations # sigma and x are from Olivie and Peters (2013) Table 5 (J13 values) # They are the covariance and mean arrays for CO2 IRF uncertainty sigma = np.array( [ [0.129, -0.058, 0.017, -0.042, -0.004, -0.009], [-0.058, 0.167, -0.109, 0.072, -0.015, 0.003], [0.017, -0.109, 0.148, -0.043, 0.013, -0.013], [-0.042, 0.072, -0.043, 0.090, 0.009, 0.006], [-0.004, -0.015, 0.013, 0.009, 0.082, 0.013], [-0.009, 0.003, -0.013, 0.006, 0.013, 0.046], ] ) x = np.array([5.479, 2.913, 0.496, 0.181, 0.401, -0.472]) p_samples = multivariate_normal.rvs(x, sigma, runs) p_df = pd.DataFrame(p_samples, columns=["t1", "t2", "t3", "b1", "b2", "b3"]) p_exp = np.exp(p_df) a1 = p_exp["b1"] / (1 + p_exp["b1"] + p_exp["b2"] + p_exp["b3"]) a2 = p_exp["b2"] / (1 + p_exp["b1"] + p_exp["b2"] + p_exp["b3"]) a3 = p_exp["b3"] / (1 + p_exp["b1"] + p_exp["b2"] + p_exp["b3"]) tau1 = p_exp["t1"] tau2 = p_exp["t2"] tau3 = p_exp["t3"] for count in np.arange(runs): co2_kwargs = { "a1": a1[count], "a2": a2[count], "a3": a3[count], "tau1": tau1[count], "tau2": tau2[count], "tau3": tau3[count], } irf = joos_2013(t_horizon, **co2_kwargs) results[:, count] = irf summary = pd.DataFrame(columns=["mean", "-2sigma", "+2sigma", "5th", "95th"]) summary["mean"] = np.mean(results, axis=1) summary["+2sigma"] = summary["mean"] + (1.96 * np.std(results, axis=1)) summary["-2sigma"] = summary["mean"] - (1.96 * np.std(results, axis=1)) summary["5th"] = np.percentile(results, 5, axis=1) summary["95th"] = np.percentile(results, 95, axis=1) return summary, results