{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Reading and writing Cosmology objects\n",
    "\n",
    "In this notebook, we show a few usage examples for how to read and write `Cosmology` objects to disk."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pyccl import Cosmology"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A cosmology including parameters and associated data (e.g. distances,\n",
      "    power spectra).\n",
      "\n",
      "    .. note:: Although some arguments default to `None`, they will raise a\n",
      "              ValueError inside this function if not specified, so they are not\n",
      "              optional.\n",
      "\n",
      "    .. note:: The parameter ``Omega_g`` can be used to set the radiation density\n",
      "              (not including relativistic neutrinos) to zero. Doing this will\n",
      "              give you a model that is physically inconsistent since the\n",
      "              temperature of the CMB will still be non-zero.\n",
      "\n",
      "    .. note:: After instantiation, you can set parameters related to the\n",
      "              internal splines and numerical integration accuracy by setting\n",
      "              the values of the attributes of\n",
      "              :obj:`Cosmology.cosmo.spline_params` and\n",
      "              :obj:`Cosmology.cosmo.gsl_params`. For example, you can set\n",
      "              the generic relative accuracy for integration by executing\n",
      "              ``c = Cosmology(...); c.cosmo.gsl_params.INTEGRATION_EPSREL = 1e-5``.\n",
      "              See the module level documentation of `pyccl.core` for details.\n",
      "\n",
      "    Args:\n",
      "        Omega_c (:obj:`float`): Cold dark matter density fraction.\n",
      "        Omega_b (:obj:`float`): Baryonic matter density fraction.\n",
      "        h (:obj:`float`): Hubble constant divided by 100 km/s/Mpc; unitless.\n",
      "        A_s (:obj:`float`): Power spectrum normalization. Exactly one of A_s\n",
      "            and sigma_8 is required.\n",
      "        sigma8 (:obj:`float`): Variance of matter density perturbations at\n",
      "            an 8 Mpc/h scale. Exactly one of A_s and sigma_8 is required.\n",
      "        n_s (:obj:`float`): Primordial scalar perturbation spectral index.\n",
      "        Omega_k (:obj:`float`): Curvature density fraction.\n",
      "            Defaults to 0.\n",
      "        Omega_g (:obj:`float`): Density in relativistic species\n",
      "            except massless neutrinos. The default of `None` corresponds\n",
      "            to setting this from the CMB temperature. Note that if a non-`None`\n",
      "            value is given, this may result in a physically inconsistent model\n",
      "            because the CMB temperature will still be non-zero in the\n",
      "            parameters.\n",
      "        Neff (:obj:`float`): Effective number of massless\n",
      "            neutrinos present. Defaults to 3.044.\n",
      "        m_nu (:obj:`float` or `array`):\n",
      "            Mass in eV of the massive neutrinos present. Defaults to 0.\n",
      "            If a sequence is passed, it is assumed that the elements of the\n",
      "            sequence represent the individual neutrino masses.\n",
      "        mass_split (:obj:`str`): Type of massive neutrinos. Should\n",
      "            be one of 'single', 'equal', 'normal', 'inverted'. 'single' treats\n",
      "            the mass as being held by one massive neutrino. The other options\n",
      "            split the mass into 3 massive neutrinos. Ignored if a sequence is\n",
      "            passed in m_nu. Default is 'normal'.\n",
      "        w0 (:obj:`float`): First order term of dark energy equation\n",
      "            of state. Defaults to -1.\n",
      "        wa (:obj:`float`): Second order term of dark energy equation\n",
      "            of state. Defaults to 0.\n",
      "        T_CMB (:obj:`float`): The CMB temperature today. The default of\n",
      "            is 2.725.\n",
      "        transfer_function (:obj:`str` or :class:`~pyccl.emulators.emu_base.EmulatorPk`):\n",
      "            The transfer function to use. Defaults to 'boltzmann_camb'.\n",
      "        matter_power_spectrum (:obj:`str` or :class:`~pyccl.emulators.emu_base.EmulatorPk`):\n",
      "            The matter power spectrum to use. Defaults to 'halofit'.\n",
      "        baryonic_effects (:class:`~pyccl.baryons.baryons_base.Baryons` or `None`):\n",
      "            The baryonic effects model to use. Options are `None` (no baryonic effects), or\n",
      "            a :class:`~pyccl.baryons.baryons_base.Baryons` object.\n",
      "        mg_parametrization (:class:`~pyccl.modified_gravity.modified_gravity_base.ModifiedGravity`\n",
      "            or `None`):\n",
      "            The modified gravity parametrization to use. Options are `None` (no MG), or\n",
      "            a :class:`~pyccl.modified_gravity.modified_gravity_base.ModifiedGravity` object. \n",
      "            Currently, only :class:`~pyccl.modified_gravity.MuSigmaMG` is supported.\n",
      "        extra_parameters (:obj:`dict`): Dictionary holding extra\n",
      "            parameters. Currently supports extra parameters for CAMB.\n",
      "            Details described below. Defaults to None.\n",
      "        T_ncdm (:obj:`float`): Non-CDM temperature in units of photon\n",
      "            temperature. The default is 0.71611.\n",
      "\n",
      "    Currently supported extra parameters for CAMB are:\n",
      "\n",
      "        * `halofit_version`\n",
      "        * `HMCode_A_baryon`\n",
      "        * `HMCode_eta_baryon`\n",
      "        * `HMCode_logT_AGN`\n",
      "        * `kmax`\n",
      "        * `lmax`\n",
      "        * `dark_energy_model`\n",
      "\n",
      "    Consult the CAMB documentation for their usage. These parameters are passed\n",
      "    in a :obj:`dict` to `extra_parameters` as::\n",
      "\n",
      "        extra_parameters = {\"camb\": {\"halofit_version\": \"mead2020_feedback\",\n",
      "                                     \"HMCode_logT_AGN\": 7.8}}\n",
      "\n",
      "    .. note :: If using camb to compute the non-linear power spectrum with HMCode\n",
      "               to include baryonic effects, you should not include any extra\n",
      "               baryonic effects (i.e. set `baryonic_effects=None`).\n",
      "    \n"
     ]
    }
   ],
   "source": [
    "cosmo = Cosmology(Omega_c=0.25, Omega_b=0.05, sigma8=0.8, h=0.7, n_s=0.96)\n",
    "print(cosmo.__doc__)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Serialization (writing parameters to disk)\n",
    "\n",
    "Cosmology objects can be saved to a YAML format using the `write_yaml` method. This format is not currently very robust -- the exact order of the parameters must be maintained or the object cannot be read back in."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Omega_c: 0.25\n",
      "Omega_b: 0.05\n",
      "h: 0.7\n",
      "n_s: 0.96\n",
      "sigma8: 0.8\n",
      "A_s: null\n",
      "Omega_k: 0.0\n",
      "Omega_g: null\n",
      "Neff: 3.044\n",
      "m_nu: 0.0\n",
      "mass_split: normal\n",
      "w0: -1.0\n",
      "wa: 0.0\n",
      "T_CMB: 2.7255\n",
      "T_ncdm: 0.71611\n",
      "extra_parameters: {}\n",
      "transfer_function: boltzmann_camb\n",
      "matter_power_spectrum: halofit\n"
     ]
    }
   ],
   "source": [
    "cosmo.write_yaml('example_params.yaml')\n",
    "!cat example_params.yaml"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Deserialization (reading parameters from disk)\n",
    "\n",
    "The parameters can be read back in using the `read_yaml` *class method*. Note that this must be called on the `Cosmology` class itself, as shown below, and not an instance of the class."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "cosmo2 = Cosmology.read_yaml(\"example_params.yaml\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<pyccl.cosmology.Cosmology>\n",
      "\tNeff    = 3.044\n",
      "\tOmega_b = 0.05\n",
      "\tOmega_c = 0.25\n",
      "\th       = 0.7\n",
      "\tn_s     = 0.96\n",
      "\tsigma8  = 0.8\n",
      "\textra_parameters =\n",
      "\tHASH_ACCURACY_PARAMS = 0xb6e46c24158c0e30\n"
     ]
    }
   ],
   "source": [
    "print(cosmo2)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This `Cosmology` object can then be used to obtain cosmological predictions. See the other examples in this directory, for example *Distance Calculations Example.ipynb* or the more comprehensive demo *SLAC Feb2018 Demo.ipynb*."
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Using Python Pickle\n",
    "\n",
    "`Cosmology` objects are also pickle-able, to make them easy to store on disk and to pass around in MPI environments."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pickle\n",
    "\n",
    "with open('cosmo.pkl', 'wb') as fp:\n",
    "    pickle.dump(cosmo2, fp)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<pyccl.cosmology.Cosmology>\n",
      "\tNeff    = 3.044\n",
      "\tOmega_b = 0.05\n",
      "\tOmega_c = 0.25\n",
      "\th       = 0.7\n",
      "\tn_s     = 0.96\n",
      "\tsigma8  = 0.8\n",
      "\textra_parameters =\n",
      "\tHASH_ACCURACY_PARAMS = 0xb6e46c24158c0e30\n"
     ]
    }
   ],
   "source": [
    "with open('cosmo.pkl', 'rb') as fp:\n",
    "    cosmo3 = pickle.load(fp)\n",
    "\n",
    "print(cosmo3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "ccl_dev",
   "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.10.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}