Source code for cosmofit.cosmology.models.logarithmic

"""
Logarithmic dark-energy equation of state.
"""

from __future__ import annotations

import numpy as np

from cosmofit.typing import Array, Redshift

from cosmofit.cosmology.numerics.powers import cube

from cosmofit.cosmology.core import Cosmology


[docs] class LogarithmicDE(Cosmology): r""" Logarithmic (Efstathiou) dark-energy parametrization, w(z) = w0 + wa ln(1 + z) with the resulting density evolution obtained by integrating the continuity equation exactly: rho_de(z)/rho_de0 = (1+z)^{3(1+w0)} exp[(3/2) wa ln^2(1+z)] The fourth ``w0``-``wa`` parametrization in the library, alongside CPL, JBP and BA -- and it is here because it fails differently from all three. CPL, JBP and BA all *saturate*: each has a finite ``w(z -> infinity)``, so none can express a dark energy whose equation of state keeps drifting. The logarithmic form does not saturate, which makes it the natural control case for asking whether a detected ``wa`` is telling you about the data or about the shape you assumed. Efstathiou proposed it specifically as a better fit to quintessence models' actual ``w(z)`` over ``0 < z < 4`` than a linear-in-``z`` form, and it reuses the existing ``w0``/``wa`` parameters, so it drops into any ``w0``-``wa`` comparison -- including the w0-wa plane figure -- without new machinery. Caveat ------ The ``ln^2(1+z)`` in the exponent grows without bound, so for ``wa > 0`` the dark-energy density diverges faster than any power law at high redshift, and for ``wa < 0`` it is driven to zero. Neither is pathological over the redshift range this library's datasets cover (``z < 2.5`` for BAO/SNe), but it does mean the model should not be extrapolated to recombination -- which is exactly why fitting it against the *compressed* ``"planck"`` distance priors (which integrate ``E(z)`` out to ``z ~ 1090``) needs a sanity check on the resulting ``Omega_de(z*)``, not blind trust. References ---------- Efstathiou (1999), "Constraining the equation of state of the Universe from distant Type Ia supernovae and cosmic microwave background anisotropies", MNRAS 310, 842, arXiv:astro-ph/9904356. """ MODEL_NAME = "LogarithmicDE" MODEL_LABEL = r"Logarithmic $w(z)$" # --------------------------------------------------------- def w(self, z: Redshift) -> Array: z = np.asarray(z, dtype=float) return self.w0 + self.wa * np.log1p(z) # --------------------------------------------------------- def _density_factor(self, z): r""" ``rho_de(z) / rho_de0``. From ``dln rho_de / dln(1+z) = 3(1 + w)``: int_0^z 3[1 + w0 + wa ln(1+z')] dln(1+z') = 3(1+w0) L + (3/2) wa L^2, L = ln(1+z) so the factor is ``exp`` of that. Written with ``log1p`` for accuracy at small ``z``. """ L = np.log1p(np.asarray(z, dtype=float)) return np.exp( 3.0 * (1.0 + self.w0) * L + 1.5 * self.wa * L ** 2 ) # --------------------------------------------------------- def Omega_de(self, z: Redshift) -> Array: return self.Omega_de0 * self._density_factor(z) # --------------------------------------------------------- def E(self, z: Redshift) -> Array: z = np.asarray(z, dtype=float) return np.sqrt( self.Omega_m * cube(1.0 + z) + self.Omega_k * (1.0 + z) ** 2 + self.Omega_de(z) ) # --------------------------------------------------------- def dEdz(self, z: Redshift) -> Array: z = np.asarray(z, dtype=float) # d(rho_de)/dz = rho_de * 3(1 + w(z)) / (1 + z), the # continuity equation itself -- no need to differentiate # the exponential by hand. d_omega_de = ( self.Omega_de(z) * 3.0 * (1.0 + self.w(z)) / (1.0 + z) ) return ( ( 3.0 * self.Omega_m * (1.0 + z) ** 2 + 2.0 * self.Omega_k * (1.0 + z) + d_omega_de ) / (2.0 * self.E(z)) )