{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import pyerrors as pe"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.style.use('./base_style.mplstyle')\n",
    "plt.rc('text', usetex=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Primary observables"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can load data from preprocessed pickle files which contain a list of `pyerror` `Obs`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "p_obs_names = [r'f_A', r'f_P']\n",
    "\n",
    "p_obs = {}\n",
    "for i, item in enumerate(p_obs_names):\n",
    "    p_obs[item] = pe.load_object('./data/B1k2_' + item + '.p')    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can now use the `pyerrors` function `plot_corrs` to have a quick look at the data we just read in "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 12048 characters]\n",
      "text/plain": [
       "<Figure size 640x395.55 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "pe.plot_corrs([p_obs['f_A'], p_obs['f_P']])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Secondary observables"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "One way of generating secondary observables is to write the desired math operations as for standard floats. `pyerrors` currently supports the basic arithmetic operations as well as numpy's basic trigonometric functions.\n",
    "\n",
    "We start by looking at the unimproved pcac mass $am=\\tilde{\\partial}_0 f_\\mathrm{A}/2 f_\\mathrm{P}$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "uimpr_mass = []\n",
    "for i in range(1, len(p_obs['f_A']) - 1):\n",
    "    uimpr_mass.append((p_obs['f_A'][i + 1] - p_obs['f_A'][i - 1]) / 2 / (2 * p_obs['f_P'][i]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For more complicated secondary obsevables or secondary observables we use over and over again it is often useful to define a dedicated function for it. Here is an example for the improved pcac mass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def pcac_mass(data, ca=0, **kwargs):\n",
    "    return ((data[1] - data[0]) / 2. + ca * (data[2] - 2 * data[3] + data[4])) / 2. / data[3]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we can construct the derived observable `pcac_mass` from the primary ones. Note the additional argument `ca` with which we can provide a value for the $\\mathrm{O}(a)$ improvement coefficient of the axial vector current."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "impr_mass = []\n",
    "for i in range(1, len(p_obs['f_A']) - 1):\n",
    "    impr_mass.append(pcac_mass([p_obs['f_A'][i - 1], p_obs['f_A'][i + 1], p_obs['f_P'][i - 1],\n",
    "                             p_obs['f_P'][i], p_obs['f_P'][i + 1]], ca=-0.03888694628624465))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To calculate the error of an observable we use the `gamma_method`. Let us have a look at the docstring"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "?pe.Obs.gamma_method"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can apply the `gamma_method` to the pcac mass on every time slice for both the unimproved and the improved mass."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "masses = [uimpr_mass, impr_mass]\n",
    "for i, item in enumerate(masses):\n",
    "    [o.gamma_method() for o in item]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can now have a look at the result by plotting the two lists of `Obs`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 23324 characters]\n",
      "text/plain": [
       "<Figure size 640x395.55 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "pe.plot_corrs([impr_mass, uimpr_mass], xrange=[0.5, 18.5], label=['Improved pcac mass', 'Unimproved pcac mass'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Tertiary observables"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can now construct a plateau as (tertiary) derived observable from the masses. At this point the distinction between primary and secondary observables becomes blurred. We can again and again resample objects into new observables which allows us to modulize the analysis. Note that `np.mean` and similar functions can be applied to the `Obs` as if they were real numbers."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Result\t 4.79208242e-03 +/- 2.09091228e-04 +/- 1.90500140e-05 (4.363%)\n",
      "  t_int\t 1.09826949e+00 +/- 1.84087104e-01 S = 2.00\n"
     ]
    }
   ],
   "source": [
    "pcac_plateau = np.mean(impr_mass[6:15])\n",
    "pcac_plateau.gamma_method()\n",
    "pcac_plateau.print()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can also use a weighted average with given `plateau_range` (passed to the function as kwarg)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "def weighted_plateau(data, **kwargs):\n",
    "    if 'plateau_range' in kwargs:\n",
    "        plateau_range = kwargs.get('plateau_range')\n",
    "    else:\n",
    "        raise Exception('No range given.')\n",
    "    \n",
    "    num = 0\n",
    "    den = 0\n",
    "    for i in range(plateau_range[0], plateau_range[1]):\n",
    "        if data[i].dvalue == 0.0:\n",
    "            raise Exception('Run gamma_method for input first')\n",
    "        num += 1 / data[i].dvalue * data[i]\n",
    "        den += 1 / data[i].dvalue\n",
    "    return num / den"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Result\t 4.78698515e-03 +/- 2.04149923e-04 +/- 1.85998184e-05 (4.265%)\n",
      "  t_int\t 1.06605715e+00 +/- 1.79069383e-01 S = 2.00\n"
     ]
    }
   ],
   "source": [
    "w_pcac_plateau = weighted_plateau(impr_mass, plateau_range=[6, 15])\n",
    "w_pcac_plateau.gamma_method()\n",
    "w_pcac_plateau.print()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this case the two variants of the plateau are almost identical\n",
    "\n",
    "We can now plot the data with the two plateaus"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 28936 characters]\n",
      "text/plain": [
       "<Figure size 640x395.55 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "pe.plot_corrs([impr_mass, uimpr_mass], plateau=[pcac_plateau, w_pcac_plateau], xrange=[0.5, 18.5],\n",
    "              label=['Improved pcac mass', 'Unimproved pcac mass'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Refined error analysis"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There are two way of adjusting the value of S. One can either change the class variable `Obs.S_global`. The set value is then used for all following applications of the `gamma_method`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Result\t 4.79208242e-03 +/- 2.02509166e-04 +/- 2.05063968e-05 (4.226%)\n",
      "  t_int\t 1.03021214e+00 +/- 1.94552148e-01 S = 3.00\n"
     ]
    }
   ],
   "source": [
    "pe.Obs.S_global = 3.0\n",
    "pcac_plateau.gamma_method()\n",
    "pcac_plateau.print()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Alternatively one can call the gamma_method with the keyword argument S. This value overwrites the global value only for the current application of the `gamma_method`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Result\t 4.79208242e-03 +/- 2.04669865e-04 +/- 1.97135904e-05 (4.271%)\n",
      "  t_int\t 1.05231340e+00 +/- 1.88061498e-01 S = 2.50\n"
     ]
    }
   ],
   "source": [
    "pcac_plateau.gamma_method(S=2.5)\n",
    "pcac_plateau.print()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can have a look at the respective normalized autocorrelation function (rho) and the integrated autocorrelation time"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 18224 characters]\n",
      "text/plain": [
       "<Figure size 640x395.55 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 16032 characters]\n",
      "text/plain": [
       "<Figure size 640x395.55 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "pcac_plateau.plot_rho()\n",
    "pcac_plateau.plot_tauint()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Critical slowing down"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`pyerrors` also supports the critical slowing down analysis of arXiv:1009.5228"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Result\t 4.79208242e-03 +/- 2.28649024e-04 +/- 1.67571716e-05 (4.771%)\n",
      "  t_int\t 1.31333644e+00 +/- 5.19554793e-01 tau_exp = 10.00,  N_sigma = 1\n"
     ]
    }
   ],
   "source": [
    "pcac_plateau.gamma_method(tau_exp=10, N_sigma=1)\n",
    "pcac_plateau.print()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The attached tail, which takes into account long range autocorrelations, is shown in the plots for rho and tauint"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 20140 characters]\n",
      "text/plain": [
       "<Figure size 640x395.55 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 21140 characters]\n",
      "text/plain": [
       "<Figure size 640x395.55 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "pcac_plateau.plot_rho()\n",
    "pcac_plateau.plot_tauint()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Additional information on the ensembles and replicas can be printed with print level 2 (In this case there is only one ensemble with one replicum.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Result\t 4.79208242e-03 +/- 2.28649024e-04 +/- 1.67571716e-05 (4.771%)\n",
      "  t_int\t 1.31333644e+00 +/- 5.19554793e-01 tau_exp = 10.00,  N_sigma = 1\n",
      "1024 samples in 1 ensembles:\n",
      " : ['B1k2r2']\n"
     ]
    }
   ],
   "source": [
    "pcac_plateau.print(2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The Monte Carlo history of the observable can be accessed with `plot_history` to identify possible outliers or have a look at the shape of the distribution"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 34328 characters]\n",
      "text/plain": [
       "<Figure size 640x395.55 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "pcac_plateau.plot_history()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If everything is satisfactory, dump the `Obs` in a pickle file for future use. The `Obs` `pcac_plateau` conatains all relevant information for any follow up analyses."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "pcac_plateau.dump('B1k2_pcac_plateau')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "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.6.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
