Source code for horizonground.clustering_modification

r"""
Clustering modification (:mod:`~horizonground.clustering_modification`)
===========================================================================

Compute modifications to the Newtonian power spectrum in the
distant-observer and plane-parallel limits.


Standard Kaiser RSD model
---------------------------------------------------------------------------

Redshift-space distortions induce anisotropy in the power spectrum
multipoles

.. math::

    \begin{align*}
        P_0(k, z) &=
            \left[
                b_1(z)^2 + \frac{2}{3} b_1(z) f(z) + \frac{1}{5} f(z)^2
            \right] P_\mathrm{m}(k, z) \,, \\
        P_2(k, z) &=
            \left[
                \frac{4}{3} b_1(z) f(z) + \frac{4}{7} f(z)^2
            \right] P_\mathrm{m}(k, z) \,, \\
        P_4(k, z) &= \frac{8}{35} f(z)^2 P_\mathrm{m}(k, z) \,
    \end{align*}

where :math:`P_\mathrm{m}` is the matter power spectrum, :math:`b_1(z)` is
the linear bias and :math:`f(z)` is the linear growth rate.

.. autosummary::

    standard_kaiser_factor


Non-Gaussianity scale-dependent modifications
---------------------------------------------------------------------------

Local primordial non-Gaussianty :math:`f_\mathrm{NL}` induces scale
dependence in the linear bias,

.. math::

    b_1(z) \mapsto b_1(z) + \Delta b_k(z) \,, \quad
    \Delta b(k, z) = f_\mathrm{NL} [b_1(z) - p] \frac{A(k, z)}{k^2} \,,

where the scale-dependence kernel is

.. math::

    A(k, z) = 3 \left( \frac{H_0}{\mathrm{c}} \right)^2
        \frac{1.27 \varOmega_\mathrm{m,0} \delta_\mathrm{c}}{D(z)T(k)} \,.

Here :math:`H_0` is the Hubble parameter at the current epoch
(in km/s/Mpc), :math:`\mathrm{c}` the speed of light,
:math:`\varOmega_\mathrm{m,0}` the matter density parameter at the current
epoch, and :math:`\delta_\mathrm{c}` the critical over-density in
spherical gravitational collapse.  The growth factor :math:`D(z)` is
normalised to unity at the current epoch (thus the numerical factor 1.27),
the transfer function :math:`T(k)` is normalised to unity as
:math:`k \to 0`, and :math:`p` is a tracer-dependent parameter.

Modifications to power spectrum multipoles as a result of local primordial
non-Gaussianty are

.. math::

    \begin{align*}
        \Delta P_0(k, z) &= \left[
            \left( 2 b_1 + \frac{2}{3} f \right) \Delta b(k, z)
            + \Delta b(k, z)^2
        \right] P_\mathrm{m}(k, z) \,, \\
        \Delta P_2(k, z) &=
            \frac{4}{3} f \Delta b(k, z) P_\mathrm{m}(k, z) \,.
    \end{align*}

.. autosummary::

    scale_dependence_kernel
    non_gaussianity_correction_factor


Relativistic corrections
---------------------------------------------------------------------------

Relativistic corrections to the Newtonian clustering mode

.. math::

    \delta(\mathbf{k}, z)
    = b_1(z) \delta_\mathrm{m}(\mathbf{k}, z)
        + g(z) v_{\parallel}(\mathbf{k}, z)
    = b_1(z) \delta_\mathrm{m}(\mathbf{k}, z)
        + \mathrm{i} \frac{\mathcal{H}}{k} g(z) f(z) \mu
        \delta_\mathrm{m}(\mathbf{k}, z)

are parametrised by the redshift-dependent, dimensionless quantity

.. math::

    g(z) = \frac{\mathcal{H}'}{\mathcal{H}^2}
        + 5s + \frac{2 - 5s}{\mathcal{H} \chi}
        - b_\mathrm{e}

with evolution bias :math:`b_\mathrm{e}(z)` and magnification bias
:math:`s(z)`, where :math:`v_{\parallel}` is the line-of-sight peculiar
velocity, :math:`\chi(z)` is the comoving distance and :math:`'` denotes
derivatives with respect to the conformal time. This can be written as the
sum of three contributions

.. math::

    g(z) = \underbrace{\left[
        1
        - \frac{3}{2} \frac{H_0^2}{H(z)^2} \varOmega_\mathrm{m,0} (1 + z)^3
        + \frac{2}{\mathcal{H}\chi}
    \right]}_{\text{background expansion}}
    \underbrace{- b_\mathrm{e}(z)}_{\text{evolution}}
    + \underbrace{
        5s(z) \left( 1 - \frac{1}{\mathcal{H}\chi} \right)
    }_{\text{magnification}} \,.

Modifications to power spectrum multipoles from the relativistic
corrections are

.. math::

    \begin{align*}
        \Delta P_0(k, z) &= \frac{1}{3} \frac{\mathcal{H}^2}{k^2}
            g(z)^2 f(z)^2 P_\mathrm{m}(k,z) \,,\\
        \Delta P_2(k, z) &= \frac{2}{3} \frac{\mathcal{H}^2}{k^2}
            g(z)^2 f(z)^2 P_\mathrm{m}(k,z) \,,
    \end{align*}

.. autosummary::

    relativistic_correction_func
    relativistic_correction_value
    relativistic_correction_factor

|

"""
# pylint: disable=no-name-in-module
import numpy as np
from astropy.constants import c
from nbodykit.lab import cosmology as nbk_cosmology

_SPEED_OF_LIGHT_IN_KM_PER_S = c.to('km/s').value
_SPHERICAL_COLLAPSE_CRITICAL_OVERDENSITY = 1.686
_GROWTH_FACTOR_NORMALISATION = 1.27

FIDUCIAL_COSMOLOGY = nbk_cosmology.Planck15
r""":class:`nbodykit.cosmology.Cosmology`: Default Planck15 cosmology.

"""


[docs]def standard_kaiser_factor(order, bias, redshift, cosmo=FIDUCIAL_COSMOLOGY): r"""Compute the standard Kaiser power spectrum multipoles as multiples of the matter power spectrum, i.e. :math:`P_\ell/P_\mathrm{m}`. Parameters ---------- order : int Order of the multipole, ``order >= 0``. bias : float Scale-independent linear bias at `redshift`. redshift : float Redshift. cosmo : :class:`nbodykit.cosmology.Cosmology`, optional Cosmological model (default is ``FIDUCIAL_COSMOLOGY``). Returns ------- factor : float Power spectrum multipoles as multiples of the matter power spectrum. """ b_1 = bias f = cosmo.scale_independent_growth_rate(redshift) if order == 0: factor = b_1 ** 2 + 2./3. * f * b_1 + 1./5. * f**2 elif order == 2: factor = 4./3. * f * b_1 + 4./7. * f**2 elif order == 4: factor = 8./35. * f**2 else: factor = 0. return factor
[docs]def scale_dependence_kernel(redshift, cosmo=FIDUCIAL_COSMOLOGY): r"""Return the scale-dependence kernel :math:`A(k, z)` in the presence of local primordial non-Gaussianity. Parameters ---------- redshift : float Redshift. cosmo : :class:`nbodykit.cosmology.Cosmology`, optional Cosmological model (default is ``FIDUCIAL_COSMOLOGY``). Returns ------- callable Scale-dependence kernel as a function of wavenumber (in :math:`h/\mathrm{Mpc}`). """ numerical_constants = 3 * _SPHERICAL_COLLAPSE_CRITICAL_OVERDENSITY \ * cosmo.Om0 * _GROWTH_FACTOR_NORMALISATION \ * (FIDUCIAL_COSMOLOGY.H0 / _SPEED_OF_LIGHT_IN_KM_PER_S)**2 transfer_function = nbk_cosmology.power.transfers.CLASS(cosmo, redshift) return lambda k: numerical_constants / transfer_function(k)
[docs]def non_gaussianity_correction_factor(wavenumber, order, local_png, bias, redshift, cosmo=FIDUCIAL_COSMOLOGY, tracer_p=1.): r"""Compute modifications to the power spectrum multipoles by local primordial non-Gaussianity as multiples of the matter power spectrum, i.e. :math:`\Delta P_\ell/P_\mathrm{m}`. Parameters ---------- wavenumber : float, array_like Wavenumber (in :math:`h/\mathrm{Mpc}`). order : int Order of the multipole, ``order >= 0``. local_png : float Local primordial non-Gaussianity. bias : float Scale-independent linear bias at `redshift`. redshift : float Redshift. cosmo : :class:`nbodykit.cosmology.Cosmology`, optional Base cosmological model (default is ``FIDUCIAL_COSMOLOGY``). tracer_p : float, optional Tracer parameter (default is 1.). Returns ------- factor : float :class:`numpy.ndarray` Power spectrum multipole modifications as multiples of the matter power spectrum. """ f_nl, p = local_png, tracer_p b_1 = bias(redshift) if callable(bias) else bias f = cosmo.scale_independent_growth_rate(redshift) delta_b = f_nl * (b_1 - p) \ * scale_dependence_kernel(redshift, cosmo=cosmo)(wavenumber) \ / wavenumber**2 if order == 0: factor = (2 * b_1 + 2./3. * f) * delta_b + delta_b ** 2 elif order == 2: factor = 4./3. * f * delta_b else: factor = 0. return factor
[docs]def relativistic_correction_func(cosmo=FIDUCIAL_COSMOLOGY, geometric=True, evolution_bias=None, magnification_bias=None): r"""Return the relativistic correction function as :math:`\mathcal{H} g(z)`. Parameters ---------- cosmo : :class:`nbodykit.cosmology.Cosmology`, optional Cosmological model (default is ``FIDUCIAL_COSMOLOGY``). geometric : bool, optional If `True` (default), include geometric contributions from the background expansion. evolution_bias, magnification_bias : callable or None, optional Evolution bias or magnification bias as a function of redshift (default is `None`). Returns ------- callable Relativistic correction function as a function of redshift (in :math:`h`/Mpc). """ astropy_cosmo = cosmo.to_astropy() aH = lambda z: astropy_cosmo.scale_factor(z) \ * astropy_cosmo.H(z).value / _SPEED_OF_LIGHT_IN_KM_PER_S chi = lambda z: astropy_cosmo.comoving_distance(z).value if geometric: geometric_term = lambda z: \ 1 - 3./2. * astropy_cosmo.Om0 \ * (astropy_cosmo.H0 / astropy_cosmo.H(z)) ** 2 \ * (1 + z) ** 3 else: geometric_term = lambda z: 0. if evolution_bias is None: evolution_term = lambda z: 0. else: evolution_term = lambda z: 2 / (aH(z) * chi(z)) - evolution_bias(z) if magnification_bias is None: lensing_term = lambda z: 0. else: lensing_term = lambda z: \ 5 * magnification_bias(z) * (1 - 1 / (aH(z) * chi(z))) return np.vectorize( lambda z: aH(z) / astropy_cosmo.h * (geometric_term(z) + evolution_term(z) + lensing_term(z)) )
[docs]def relativistic_correction_value(redshift, cosmo=FIDUCIAL_COSMOLOGY, geometric=True, evolution_bias=None, magnification_bias=None): r"""Evaluate the relativistic correction function :math:`\mathcal{H} g(z)` at a given redshift. Parameters ---------- redshift : float Redshift. cosmo : :class:`nbodykit.cosmology.Cosmology`, optional Base cosmological model (default is ``FIDUCIAL_COSMOLOGY``). geometric : bool, optional If `True` (default), include geometric contributions from the background expansion. evolution_bias, magnification_bias : float or None, optional Evolution bias or magnification bias evaluated at input `redshift` (default is `None`). Returns ------- correction_value : float Relativistic correction function value (in :math:`h`/Mpc) at `redshift`. """ astropy_cosmo = cosmo.to_astropy() aH = astropy_cosmo.scale_factor(redshift) \ * astropy_cosmo.H(redshift).value / _SPEED_OF_LIGHT_IN_KM_PER_S chi = astropy_cosmo.comoving_distance(redshift).value correction_value = 0. if geometric: correction_value += 1 - 3./2. * astropy_cosmo.Om0 \ * (astropy_cosmo.H0 / astropy_cosmo.H(redshift)) ** 2 \ * (1 + redshift) ** 3 if evolution_bias: correction_value += 2 / (aH * chi) - evolution_bias if magnification_bias: correction_value += 5 * magnification_bias * (1 - 1 / (aH * chi)) return aH / astropy_cosmo.h * correction_value
[docs]def relativistic_correction_factor(wavenumber, order, redshift, correction_value=None, cosmo=FIDUCIAL_COSMOLOGY, geometric=True, evolution_bias=None, magnification_bias=None): r"""Compute modifications to the power spectrum multipoles by relativistic corrections as multiples of the matter power spectrum, i.e. :math:`\Delta P_\ell/P_\mathrm{m}`. Parameters ---------- wavenumber : float, array_like Wavenumber (in :math:`h/\mathrm{Mpc}`). order : int Order of the multipole, ``order >= 0``. redshift : float Redshift. correction_value : float or None, optional If not `None` (default), this is directly used as :math:`\mathcal{H} g(z)` at `redshift` in calculations, and `cosmo`, `geometric`, `evolution_bias` and `magnification_bias` are ignored. cosmo : :class:`nbodykit.cosmology.Cosmology`, optional Cosmological model (default is ``FIDUCIAL_COSMOLOGY``). geometric : bool, optional If `True` (default), include geometric contributions from the background expansion. evolution_bias : float or callable or None, optional Evolution bias as a function of redshift, or evaluated at input `redshift` (default is `None`). If callable/float, `magnification_bias` must also be callable/float. magnification_bias : float or callable or None, optional Magnification bias as a function of redshift, or evaluated at input `redshift` (default is `None`). If callable/float, `evolution_bias` must also be callable/float. Returns ------- factor : float :class:`numpy.ndarray` Power spectrum multipoles as multiples of the matter power spectrum. """ if correction_value is None: if callable(evolution_bias) and callable(magnification_bias): correction_function = relativistic_correction_func( cosmo=cosmo, geometric=geometric, evolution_bias=evolution_bias, magnification_bias=magnification_bias ) correction_value = correction_function(redshift) elif isinstance(evolution_bias, float) \ and isinstance(magnification_bias, float): correction_value = relativistic_correction_value( redshift, cosmo=cosmo, geometric=geometric, evolution_bias=evolution_bias, magnification_bias=magnification_bias ) elif evolution_bias is None and magnification_bias is None: correction_value = relativistic_correction_value( redshift, cosmo=cosmo, geometric=geometric ) else: raise TypeError( "`evolution_bias` and `magnification_bias` must be " "both callable or float or None." ) modification = correction_value ** 2 \ * cosmo.scale_independent_growth_rate(redshift) ** 2 \ / wavenumber ** 2 if order == 0: factor = 1./3. * modification elif order == 2: factor = 2./3. * modification else: factor = 0. return factor