{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Example 10 Backreaction"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "One of $\\texttt{DarkHistory}$'s signature features is its ability to include the effects of backreaction on the thermal and ionization histories of the universe.  In previous treatments, one assumed that the effects of dark matter energy injection were small enough that one could replace the hydrogen ionization level $x_\\text{HII}$ and the IGM temperature $T_m$ by their baseline values when computed in the absence of dark matter energy injection $x_{\\text{HII},0}$ and $T_{m,0}$.  On the other hand, $\\texttt{DarkHistory}$ can be used without this approximation.  We will see in this notebook that there is a wide range of models for which this improved treatment is necessary."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Import Modules"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%reload_ext autoreload\n",
    "%autoreload 2\n",
    "import sys\n",
    "sys.path.append(\"..\")\n",
    "\n",
    "import matplotlib\n",
    "import matplotlib.pyplot as plt\n",
    "matplotlib.rc_file('matplotlibrc')\n",
    "\n",
    "from scipy.interpolate import interp1d\n",
    "from scipy.interpolate import interp2d\n",
    "import numpy as np\n",
    "\n",
    "import darkhistory.physics as phys\n",
    "from darkhistory.history.tla import get_history\n",
    "\n",
    "import darkhistory.main as main\n",
    "import darkhistory.config as config\n",
    "from tqdm import tqdm_notebook as tqdm"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Load the maximum allowed $\\langle \\sigma v \\rangle$ and minimum $\\tau$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To assess the effects of backreaction, we will compute $T_m(z)$ with and without backreaction for the cases of dark matter decaying or annihilating into $\\gamma \\gamma$ or $e^+ e^-$, and we will sweep over a wide range of dark matter masses, $m_\\chi$.  The effects of backreaction are amplified as the lifetime $\\tau$ is decreased or the velocity-averaged cross-section $\\langle \\sigma v \\rangle$ is increased.  We will therefore use the maximum $\\langle \\sigma v \\rangle$ and minimum $\\tau$ allowed by current CMB constraints [[1]](#cite_Tracy2015), [[2]](#cite_Chih_Liang), [[3]](#cite_PLANCK).  We download these maximal values as a function of secondary particle injection energy $E_\\text{inj}$.  The CMB limit data has been included in the downloaded data from [*here*](https://doi.org/10.7910/DVN/DUOUWA).\n",
    "\n",
    "Note: It is important when downloading the 'CMB_limits*' files that the 'Original Format' option is chosen to ensure that the two .csv files containing the decay limits are downloaded correctly."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "f_elec_CMB_raw = np.loadtxt(config.data_path+'/CMB_limits_elec_swave.txt', delimiter=',')\n",
    "log10eng_elec_CMB  = f_elec_CMB_raw[0:2760:69, 0]\n",
    "log10rs_elec_CMB = f_elec_CMB_raw[0:69, 1]\n",
    "\n",
    "f_phot_CMB_raw = np.loadtxt(config.data_path+'/CMB_limits_phot_swave.txt', delimiter=',')\n",
    "log10eng_phot_CMB  = f_phot_CMB_raw[0:2800:70, 0]\n",
    "log10rs_phot_CMB = f_phot_CMB_raw[0:70, 1]\n",
    "\n",
    "f_elec_CMB_raw = np.transpose(np.reshape(f_elec_CMB_raw[:,2], (40,69)))\n",
    "f_phot_CMB_raw = np.transpose(np.reshape(f_phot_CMB_raw[:,2], (40,70)))\n",
    "\n",
    "f_elec_CMB = interp2d(log10eng_elec_CMB, log10rs_elec_CMB, f_elec_CMB_raw)\n",
    "f_phot_CMB = interp2d(log10eng_phot_CMB, log10rs_phot_CMB, f_phot_CMB_raw)\n",
    "\n",
    "decay_elec_CMB_raw = np.loadtxt(config.data_path+'/CMB_limits_elec_decay.txt', delimiter=',')\n",
    "decay_phot_CMB_raw = np.loadtxt(config.data_path+'/CMB_limits_phot_decay.txt', delimiter=',')\n",
    "\n",
    "decay_elec_CMB = interp1d(np.transpose(decay_elec_CMB_raw)[0,:], np.transpose(decay_elec_CMB_raw)[1,:])\n",
    "decay_phot_CMB = interp1d(np.transpose(decay_phot_CMB_raw)[0,:], np.transpose(decay_phot_CMB_raw)[1,:])\n",
    "\n",
    "#Derived from Planck 2018 cosmological parameters\n",
    "p_ann = 3.5e-28\n",
    "\n",
    "def xsec_bound_elec_CMB(mDM, DM_process):\n",
    "    if DM_process == 'swave':\n",
    "        return p_ann*(mDM*1e-9)/f_elec_CMB(np.log10(mDM-phys.me), np.log10(601))[0]\n",
    "    elif DM_process == 'decay':\n",
    "        return np.array([decay_elec_CMB(mDM*1e-9)])[0]\n",
    "\n",
    "def xsec_bound_phot_CMB(mDM, DM_process):\n",
    "    if DM_process == 'swave':\n",
    "        return p_ann*(mDM*1e-9)/f_phot_CMB(np.log10(mDM), np.log10(601))[0]\n",
    "    elif DM_process == 'decay':\n",
    "        return np.array([decay_phot_CMB(mDM*1e-9)])[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Comparison to Fig. 15 of [[4]](#cite_Hongwan)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To get a feel for the calculation and check $\\texttt{DarkHistory}$ we will try to reproduce Fig 15. of [[4]](#cite_Hongwan).  First we establish the baseline (black-dashed curve) without dark matter energy injection.  This can be done by passing a redshift vector to [*tla.get_history()*](https://darkhistory.readthedocs.io/en/master/_autosummary/darkhistory/history/tla/darkhistory.history.tla.get_history.html)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "rs_vec = 3000*np.exp(-.004*np.arange(1595))\n",
    "        \n",
    "baseline = get_history(rs_vec)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we calculate $T_m(z)$ assuming no backreaction. To do so, we will use tabulated values for $f_c(z)$ and use them as inputs for [*tla.get_history()*](https://darkhistory.readthedocs.io/en/master/_autosummary/darkhistory/history/tla/darkhistory.history.tla.get_history.html).  We can do this by inputting `baseline_f = True`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "no_br = get_history(\n",
    "    rs_vec, baseline_f = True,\n",
    "    inj_particle = 'elec', DM_process = 'decay',\n",
    "    mDM=100e6, lifetime = 3e25,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, we calculate $T_m(z)$ including backreaction by using [*main.evolve()*](https://darkhistory.readthedocs.io/en/master/_autosummary/main/main.evolve.html).  This will take a while the first time it is run because we must download the transfer functions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "br_data = main.evolve(\n",
    "    primary='elec_delta',\n",
    "    DM_process='decay', mDM=100e6, lifetime=3e25,\n",
    "    start_rs = 3000,\n",
    "    coarsen_factor=16, backreaction=True\n",
    ")\n",
    "\n",
    "T_br = br_data['Tm']/phys.kB"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, we re-make Fig 15."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fig_BR_example = plt.figure(figsize=(15,6.5))\n",
    "\n",
    "ax = plt.subplot(1,2,1)\n",
    "\n",
    "ax = plt.gca()\n",
    "ax.loglog()\n",
    "\n",
    "plt.xlabel('Redshift $(1+z)$')\n",
    "plt.ylabel('Matter Temperature $T_m$ [K]')\n",
    "\n",
    "plt.title(r'\\bf{Backreaction Comparison}')\n",
    "\n",
    "plt.axis([5, 3e3, 1, 1e5])\n",
    "\n",
    "plot_std, = plt.plot(rs_vec, baseline[:,0]/phys.kB, 'k--', label='Baseline')\n",
    "plot_no_BR, = plt.plot(rs_vec, no_br[:,0]/phys.kB, label='Without Backreaction', color='C0')\n",
    "plot_BR, = plt.plot(br_data['rs'], br_data['Tm']/phys.kB, label='With Backreaction', color='C1')\n",
    "\n",
    "plt.text(0.06, 0.9, r'$\\chi \\to e^+e^-$, $m_\\chi$ = 100 MeV', transform=ax.transAxes, fontsize=20)\n",
    "plt.text(0.06, 0.84, r'$\\tau = 3 \\times 10^{25}$ s', transform=ax.transAxes, fontsize=20)\n",
    "\n",
    "legend = plt.legend(\n",
    "    handles=[plot_no_BR, plot_BR, plot_std], loc='lower right'\n",
    ")\n",
    "\n",
    "ax = plt.subplot(1,2,2)\n",
    "\n",
    "ax = plt.gca()\n",
    "ax.loglog()\n",
    "\n",
    "plt.xlabel('Redshift $(1+z)$')\n",
    "plt.ylabel('Hydrogen Ionization Fraction $n_\\mathrm{HII}/n_\\mathrm{H}$')\n",
    "\n",
    "plt.title(r'\\bf{Backreaction Comparison}')\n",
    "\n",
    "plt.axis([5, 3e3, 7e-6, 2])\n",
    "\n",
    "plot_std, = plt.plot(rs_vec, baseline[:,1], 'k--', label='Baseline')\n",
    "plot_no_BR, = plt.plot(rs_vec, no_br[:,1], label='Without Backreaction', color='C0')\n",
    "plot_BR, = plt.plot(br_data['rs'], br_data['x'][:,0], label='With Backreaction', color='C1')\n",
    "\n",
    "plt.text(0.06, 0.9, r'$\\chi \\to e^+e^-$, $m_\\chi$ = 100 MeV', transform=ax.transAxes, fontsize=20)\n",
    "plt.text(0.06, 0.84, r'$\\tau = 3 \\times 10^{25}$ s', transform=ax.transAxes, fontsize=20)\n",
    "\n",
    "legend = plt.legend(\n",
    "    handles=[plot_no_BR, plot_BR, plot_std], loc='lower right'\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Calculate With and Without back-reaction"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we perform the same calculation, except now over a grid of energy injections.  We first specify these energies, then we define the function `get_T()` to easily calculate $T_m$ for a given mass and injection model with and without backreaction."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "log10_Einj_arr = np.arange(4.01, 12.51, 0.25)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When computing s-wave annihilation models, we must remember that structure formation now boosts the annihilation rate at late times. We can load one of DarkHistory's default structure formation boost factors that can be obtained using the function [*physics.struct_boost_func()*](https://darkhistory.readthedocs.io/en/master/_autosummary/darkhistory/physics/darkhistory.physics.struct_boost_func.html). The first thing we need to do is obtain the function that returns the boost: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct_boost_einasto_subs = phys.struct_boost_func(model='einasto_subs')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%autoreload\n",
    "\n",
    "def get_T(mDM, DM_process, br, pri):\n",
    "    \"\"\"Gets the temperature history, decays.\n",
    "    \n",
    "    Parameters\n",
    "    ----------\n",
    "    mDM : float\n",
    "        The mass of the dark matter in eV. \n",
    "    tau : float\n",
    "        The decay lifetime in s. \n",
    "    br : bool\n",
    "        Whether to use backreaction or not. \n",
    "    pri : {'elec', 'phot'}\n",
    "        The primary particles that DM decays to. \n",
    "        \n",
    "    Returns\n",
    "    --------\n",
    "    float\n",
    "        The temperature history in K. \n",
    "    \n",
    "    \"\"\"\n",
    "    \n",
    "    if pri == 'elec':\n",
    "        pri_str = 'elec_delta'\n",
    "        cf = 12\n",
    "        param = xsec_bound_elec_CMB(mDM, DM_process)\n",
    "        rs_vec = 3000*np.exp(-.012*np.arange(552))\n",
    "    if pri == 'phot':\n",
    "        pri_str = 'phot_delta'\n",
    "        cf = 4\n",
    "        param = xsec_bound_phot_CMB(mDM, DM_process)\n",
    "        rs_vec = 3000*np.exp(-.004*np.arange(1655))\n",
    "        \n",
    "    if DM_process == 'swave':\n",
    "        struct_boost = phys.struct_boost_func(model='einasto_subs')\n",
    "    else:\n",
    "        struct_boost = None\n",
    "        \n",
    "    if br:\n",
    "        result = main.evolve(\n",
    "            primary=pri_str,\n",
    "            DM_process=DM_process, mDM=mDM, lifetime=param, sigmav = param,\n",
    "            start_rs = 3000, end_rs=4.004,\n",
    "            coarsen_factor=cf, backreaction=False,\n",
    "            struct_boost = struct_boost\n",
    "        )\n",
    "        \n",
    "        return result['Tm']/phys.kB\n",
    "    \n",
    "    else:\n",
    "\n",
    "        if pri == 'phot' and DM_process == 'swave':\n",
    "            # Use main.evolve() here because the differential is so small that\n",
    "            # using f_std leads to undesirable interpolation errors.\n",
    "            result = main.evolve(\n",
    "                primary=pri_str,\n",
    "                DM_process=DM_process, mDM=mDM, lifetime=param, sigmav = param,\n",
    "                start_rs = 3000, end_rs=4.004,\n",
    "                coarsen_factor=cf, backreaction=False,\n",
    "                struct_boost = struct_boost\n",
    "            )\n",
    "            \n",
    "            return result['Tm']/phys.kB\n",
    "\n",
    "        else:\n",
    "            result = get_history(\n",
    "                rs_vec, baseline_f = True,\n",
    "                inj_particle = pri, DM_process = DM_process,\n",
    "                mDM=mDM, lifetime = param, sigmav = param\n",
    "            )\n",
    "            \n",
    "            return result[:,0]/phys.kB"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We now loop over all injection energies and calculate $T_m$ for decay or annihilation into photons or $e^+e^-$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "Tm_no_br = np.array([None for m in log10_Einj_arr])\n",
    "Tm_br = np.zeros_like(Tm_no_br)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%autoreload\n",
    "for i, log10Einj in enumerate(tqdm(log10_Einj_arr)):\n",
    "    \n",
    "    Einj = 10**log10Einj\n",
    "    print('****** log10(mDM): ', log10Einj, ' ******')\n",
    "\n",
    "    Tm_no_br[i] = {\n",
    "        'phot_decay': get_T(2*Einj, 'decay', br=False, pri='phot'),\n",
    "        # We include this little fudge factor here because python's ode solver will sometimes guess negative \n",
    "        # values for the redshift at certain values of Einj\n",
    "        'phot_swave': get_T(Einj+1e-4, 'swave', br=False, pri='phot'),\n",
    "        'elec_swave': get_T(Einj+phys.me, 'swave', br=False, pri='elec'),\n",
    "        'elec_decay': get_T(2*(Einj+phys.me), 'decay', br=False, pri='elec')\n",
    "    }\n",
    "\n",
    "print('###### Calculation Complete! ######')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And then we calculate with back-reaction"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%autoreload\n",
    "for i, log10Einj in enumerate(tqdm(log10_Einj_arr)):\n",
    "    \n",
    "    Einj = 10**log10Einj\n",
    "    print('****** log10(mDM): ', log10Einj, ' ******')\n",
    "    \n",
    "    Tm_br[i] = {\n",
    "        'phot_decay': get_T(2*Einj, 'decay', br=True, pri='phot'),\n",
    "        'phot_swave': get_T(Einj, 'swave', br=True, pri='phot'),\n",
    "        'elec_swave': get_T(Einj+phys.me, 'swave', br=True, pri='elec'),\n",
    "        'elec_decay': get_T(2*(Einj+phys.me), 'decay', br=True, pri='elec')\n",
    "    }\n",
    "\n",
    "print('###### Calculation Complete! ######')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Heat Plots of the Effects of Backreaction"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we save the data we just generated or load data what we've previously generated.  `direc` should be set to the directory where the data was (or will be) saved, e.g. `direc=/directory/where/the/data/gets/saved/`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pickle\n",
    "save_data = False\n",
    "direc = '/foo/bar/'\n",
    "\n",
    "if save_data:\n",
    "    pickle.dump(Tm_no_br, open(direc+'Tm_no_br.p','wb'))\n",
    "    pickle.dump(Tm_br, open(direc+'Tm_br.p','wb'))\n",
    "else:\n",
    "    Tm_no_br = pickle.load(open(direc+'Tm_no_br.p','rb'))\n",
    "    Tm_br = pickle.load(open(direc+'Tm_br.p','rb'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And then we plot our data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "inj_part = 'phot'\n",
    "inj_type = 'swave'\n",
    "\n",
    "log10_Einj_arr = np.arange(4.01, 12.51, 0.25)\n",
    "log10_Einj_elec_decay_arr = np.arange(4.01, 12.51, 0.25)\n",
    "log10_E = log10_Einj_arr\n",
    "\n",
    "diff_list = np.array([Tm_br0[k][inj_part+'_'+inj_type]/Tm_no_br0[k][inj_part+'_'+inj_type]-1. for k in np.arange(34)])\n",
    "diff_list[diff_list<=0]=.001\n",
    "        \n",
    "if inj_part == 'phot':\n",
    "    cf=4\n",
    "    if inj_type == 'decay':\n",
    "        conv_fac = 2\n",
    "        conv_add = 0\n",
    "    else:\n",
    "        conv_fac = 1\n",
    "        conv_add = 0\n",
    "else:\n",
    "    if inj_type == 'swave':\n",
    "        conv_fac = 1\n",
    "        conv_add = phys.me\n",
    "    else:\n",
    "        log10_E = log10_Einj_elec_decay_arr\n",
    "        conv_fac = 2\n",
    "        conv_add = phys.me\n",
    "    cf=12\n",
    "\n",
    "rs_list = np.exp(np.arange(np.log(3000), np.log(4.004), step=-0.001*cf))\n",
    "\n",
    "plt.figure(figsize=(7.7, 6.2))\n",
    "\n",
    "ax = plt.gca()\n",
    "ax.loglog()\n",
    "\n",
    "# Specify the proper contour levels and label them\n",
    "if inj_part == 'phot':\n",
    "    if inj_type == 'decay':\n",
    "        frac_change_levels = [1e-4, 5, 10, 20, 50, 100, 200]\n",
    "        frac_change_labels = ['0\\%', '5\\%', '10\\%', '20\\%', '50\\%', '100\\%', '200\\%']\n",
    "\n",
    "    else:\n",
    "        frac_change_levels = [1e-5, .1, .5, 1, 2, 5, 10, 20, 40]\n",
    "        frac_change_labels = ['0\\%','0.1\\%', '0.5\\%', '1\\%', '2\\%', '5\\%', '10\\%', '20\\%', '40\\%']\n",
    "else:\n",
    "    if inj_type == 'decay':\n",
    "        frac_change_levels = [0.001, 5, 10, 50, 100, 200, 500, 900]\n",
    "        frac_change_labels = ['0\\%', '5\\%', '10\\%', '50\\%', '100\\%', '200\\%', '500\\%', '900\\%']\n",
    "    else:\n",
    "        frac_change_levels = [0.001, 5, 10, 20, 50, 100, 200]\n",
    "        frac_change_labels = ['0\\%', '5\\%', '10\\%', '20\\%', '50\\%', '100\\%', '200\\%']\n",
    "    \n",
    "    \n",
    "plt_heating = plt.contour(\n",
    "    (10**log10_E + conv_add)*conv_fac, rs_list, \n",
    "    np.transpose(np.abs(diff_list)*100),\n",
    "    levels=frac_change_levels,\n",
    "    linewidths=0.5,\n",
    "    colors='k'\n",
    ")\n",
    "\n",
    "cntr1 = ax.contourf((10**log10_E + conv_add)*conv_fac, \n",
    "                    rs_list, \n",
    "                    np.transpose(np.abs(diff_list)*100), \n",
    "                    frac_change_levels,\n",
    "                    norm=matplotlib.colors.LogNorm(),\n",
    "                    cmap=matplotlib.cm.inferno\n",
    ")\n",
    "\n",
    "cbar = plt.colorbar(\n",
    "    cntr1, ax=ax, ticks=frac_change_levels,\n",
    ")\n",
    "cbar.set_ticklabels(frac_change_labels)\n",
    "cbar.set_label(r'$T_m$ Fractional Change $\\delta T_m/ T_{m,0}$', labelpad=20)\n",
    "\n",
    "plt.axis([(10**log10_E[0] + conv_add)*conv_fac, (10**log10_E[-1] + conv_add)*conv_fac, 5.1, 201.61653821924926])\n",
    "\n",
    "if inj_part == 'elec':\n",
    "    if inj_type == 'decay':\n",
    "        label1_txt = r'$\\chi \\to e^+e^-$'\n",
    "        label2_txt = r'$\\tau_{\\min}$ from CMB'\n",
    "        label1_dx = -0.05\n",
    "        label2_dx = +0.12\n",
    "    else:\n",
    "        label1_txt = r'$\\chi \\chi \\to e^+e^-$'\n",
    "        label2_txt = r'$\\langle \\sigma v \\rangle_{\\max}$ from CMB'\n",
    "        label1_dx = -0.1\n",
    "        label2_dx = +0.02\n",
    "else:\n",
    "    if inj_type == 'decay':\n",
    "        label1_txt = r'$\\chi \\to \\gamma \\gamma$'\n",
    "        label2_txt = r'$\\tau_{\\min}$ from CMB'\n",
    "        label1_dx = 0.\n",
    "        label2_dx = +0.12\n",
    "    else:\n",
    "        label1_txt = r'$\\chi \\chi \\to \\gamma \\gamma$'\n",
    "        label2_txt = r'$\\langle \\sigma v \\rangle_{\\max}$ from CMB'\n",
    "        label1_dx = -0.04\n",
    "        label2_dx = +0.03\n",
    "\n",
    "plt.text(0.77+label1_dx, 0.91, label1_txt,transform=ax.transAxes, color='w', fontsize=20)\n",
    "plt.text(0.46+label2_dx, 0.83, label2_txt,transform=ax.transAxes, color='w', fontsize=20)\n",
    "\n",
    "plt.title(r'\\bf{Backreaction $T_m$ Comparison}')\n",
    "plt.ylabel(r'Redshift ($1+z$)')\n",
    "plt.xlabel(r'Dark Matter Mass $m_\\chi$ [eV]')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Bibliography"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[1]<a id='cite_Tracy2015'></a> T. R. Slatyer \"Indirect dark matter signatures in the cosmic dark ages. I. Generalizing the bound on s-wave dark matter annihilation from Planck results,\" arXiv:1506.03811, Phys. Rev. D 93, no. 2, 023527 (2016).\n",
    "  \n",
    "[2]<a id='cite_PLANCK'></a> N. Aghanim et al. (Planck), “Planck 2018 results. VI. Cosmological parameters,” (2018), arXiv:1807.06209.\n",
    "\n",
    "[3]<a id='cite_Chih_Liang'></a> T. R. Slatyer and C. Wu, “General Constraints on Dark Matter Decay from the Cosmic Microwave Background,” arXiv:1610.06933, Phys. Rev. D95, 023010 (2017).\n",
    "\n",
    "[4]<a id='cite_Hongwan'></a> Hongwan Liu, Tracy R. Slatyer, and Jesús Zavala, “Contributions to cosmic reionization from dark matter annihilation and decay,” Phys. Rev. D94, 063507 (2016),\n",
    "arXiv:1604.02457 [astro-ph.CO]."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "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.7.4"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
