Benchmarking NumCosmo vs. CCL

Author

NumCosmo developers

Published

February 9, 2025

Abstract

This document shows the NumCosmo implementation of cosmology background functions and compares it to the CCL ones.

Introduction

This notebook explores the cosmological background functions implemented in the Core Cosmology Library (CCL) and NumCosmo, two frameworks for computing cosmological quantities. We aim to assess the consistency and accuracy of distance measures, such as comoving and luminosity distances, across these frameworks by comparing their outputs under identical physical parameters. To facilitate this analysis, we first establish a set of cosmological models with fixed and variable parameters, then define a function to compute and visualize the distances alongside their relative differences. The results are summarized in tables and plots below.

import sys
import numpy as np
import math
import matplotlib.pyplot as plt
from IPython.display import HTML, Markdown, display

# CCL
import pyccl
import pandas as pd

# NumCosmo
from numcosmo_py import Nc, Ncm

from numcosmo_py.plotting.tools import set_rc_params_article, format_time
import numcosmo_py.cosmology as ncc
import numcosmo_py.ccl.comparison as nc_cmp

Initializing NumCosmo

To begin, we configure NumCosmo and redirect its output to this notebook using the following code:

Ncm.cfg_init()
Ncm.cfg_set_log_handler(lambda msg: sys.stdout.write(msg) and sys.stdout.flush())
set_rc_params_article(ncol=2, fontsize=12, use_tex=False)

Initial Parameter Definitions

We initialize the cosmological parameters and model-specific variables used for CCL and NumCosmo comparisons. Scalar parameters are fixed across all models, while arrays define variations in dark energy and neutrino properties for multiple scenarios. First, we instantiate a CCL cosmology object using the predefined global parameters. Next, using the numcosmo_py[^numcosmo_py] function create_nc_obj, we generate a NumCosmo cosmology object initialized with the same parameters as the CCL model. Fixed scalars apply universally, while arrays (\(\Omega_v\), \(w_0\), \(w_a\), \(m_\nu\)) represent different model configurations. Finally, in the setup_models function, one can enable high-precision computations in CCL, which increases accuracy at the cost of longer computation times. When this mode is activated, the overall agreement between CCL and NumCosmo improves significantly.

Code
from numcosmo_py.ccl.nc_ccl import create_nc_obj

PARAMETERS_SET = [
    r"$\Lambda$CDM, flat",
    r"$\Lambda$CDM, flat, $1\nu$",
    r"XCDM, flat",
    r"XCDM, spherical, $2\nu$",
    r"XCDM, hyperbolic",
]
COLORS = plt.rcParams["axes.prop_cycle"].by_key()["color"][:5]


def setup_models(
    Omega_c: float = 0.25,  # Cold dark matter density
    Omega_b: float = 0.05,  # Baryonic matter density
    h: float = 0.7,  # Dimensionless Hubble constant
    sigma8: float = 0.9,  # Matter density contrast std. dev. (8 Mpc/h)
    n_s: float = 0.96,  # Scalar spectral index
    Neff: float = 3.046,  # Effective number of massless neutrinos
    high_precision: bool = False,  # Use high precision computations in CCL
    dist_z_max: float = 15.0,  # Maximum redshift for distance computations
):
    """Setup cosmological models."""
    Omega_v_vals = np.array([0.7, 0.7, 0.7, 0.65, 0.75])  # Dark energy density
    w0_vals = np.array([-1.0, -1.0, -0.9, -0.9, -0.9])  # DE equation of state w0
    wa_vals = np.array([0.0, 0.0, 0.1, 0.1, 0.1])  # DE equation of state wa

    # Neutrino masses (eV) for each model: [m1, m2, m3]
    mnu = np.array(
        [
            [0.0, 0.0, 0.0],
            [0.04, 0.0, 0.0],
            [0.0, 0.0, 0.0],
            [0.03, 0.02, 0.0],
            [0.0, 0.0, 0.0],
        ]
    )
    Omega_k_vals = [
        float(1.0 - Omega_c - Omega_b - Omega_v) for Omega_v in Omega_v_vals
    ]

    parameters = [
        ["$\\Omega_c$", "Cold Dark Matter Density", Omega_c],
        ["$\\Omega_b$", "Baryonic Matter Density", Omega_b],
        ["$\\Omega_v$", "Dark Energy Density", Omega_v_vals],
        ["$\\Omega_k$", "Curvature Density", [f"{v:.3f}" for v in Omega_k_vals]],
        ["$h$", "Hubble Constant (dimensionless)", h],
        ["$n_s$", "Scalar Spectral Index", n_s],
        ["$N_\\mathrm{eff}$", "Effective Nº of Massless Neutrinos", Neff],
        ["$\\sigma_8$", "Matter Density Contrast Std. Dev. (8 Mpc/h)", sigma8],
        ["$w_0$", "DE Equation of State Parameter", w0_vals],
        ["$w_a$", "DE Equation of State Parameter", wa_vals],
        ["$m_\\nu$", "Neutrino Masses (eV)", [f"{m.tolist()}" for m in mnu]],
    ]
    models = []
    if high_precision:
        CCLParams.set_high_prec_params()

    for Omega_v, Omega_k, w0, wa, m in zip(
        Omega_v_vals, Omega_k_vals, w0_vals, wa_vals, mnu
    ):
        ccl_cosmo = pyccl.Cosmology(
            Omega_c=Omega_c,
            Omega_b=Omega_b,
            Neff=Neff,
            h=h,
            sigma8=sigma8,
            n_s=n_s,
            Omega_k=Omega_k,
            w0=w0,
            wa=wa,
            m_nu=m,
            transfer_function="eisenstein_hu",
        )
        cosmology = create_nc_obj(ccl_cosmo, dist_z_max=dist_z_max)
        models.append({"CCL": ccl_cosmo, "NC": cosmology})

    return parameters, models
# Preparing the models
parameters, models = setup_models(high_precision=False)
z = np.geomspace(0.01, 1200.0, 10000)

Parameter Overview

The table below summarizes the parameters. There are five parameters sets.

Code
# Create DataFrame
df = pd.DataFrame(parameters, columns=["Symbol", "Description", "Value"])
display(Markdown(df.to_markdown(index=False, colalign=["left"] * len(df.columns))))
Symbol Description Value
\(\Omega_c\) Cold Dark Matter Density 0.25
\(\Omega_b\) Baryonic Matter Density 0.05
\(\Omega_v\) Dark Energy Density [0.7 0.7 0.7 0.65 0.75]
\(\Omega_k\) Curvature Density [‘0.000’, ‘0.000’, ‘0.000’, ‘0.050’, ‘-0.050’]
\(h\) Hubble Constant (dimensionless) 0.7
\(n_s\) Scalar Spectral Index 0.96
\(N_\mathrm{eff}\) Effective Nº of Massless Neutrinos 3.046
\(\sigma_8\) Matter Density Contrast Std. Dev. (8 Mpc/h) 0.9
\(w_0\) DE Equation of State Parameter [-1. -1. -0.9 -0.9 -0.9]
\(w_a\) DE Equation of State Parameter [0. 0. 0.1 0.1 0.1]
\(m_\nu\) Neutrino Masses (eV) [‘[0.0, 0.0, 0.0]’, ‘[0.04, 0.0, 0.0]’, ‘[0.0, 0.0, 0.0]’, ‘[0.03, 0.02, 0.0]’, ‘[0.0, 0.0, 0.0]’]
Table 1: Used cosmological parameters in CCL and NumCosmo

Cosmology Parameters

The following function compares the total mass density (baryonic + cold dark matter + massive neutrinos), the total mass density parameter, and the normalized Hubble function. Below, we present the results for all sets of parameters.

Note that in CCL, the total matter density parameter is defined as the sum of the matter density parameter and the massive neutrino density parameter. In contrast, NumCosmo defines it as the sum of the matter density parameter and the fraction of the massive neutrino density parameter that is non-relativistic at a given redshift. For consistency, we compute \(\Omega_m\) using the CCL prescription, this is done turning the CCL_comp parameter to True in the NumCosmo cosmology object.

parameter_funcs = [
    nc_cmp.compare_Omega_m,
    nc_cmp.compare_Omega_g,
    nc_cmp.compare_Omega_nu,
    nc_cmp.compare_Omega_mnu,
]

parameter_comparisons: list[list[nc_cmp.CompareFunc1d]] = [
    [func(m["CCL"], m["NC"], z, model=name) for m, name in zip(models, PARAMETERS_SET)]
    for func in parameter_funcs
]
Code
for parameter_comparison in parameter_comparisons:
    fig, axs = plt.subplots(2, sharex=True)
    fig.subplots_adjust(hspace=0)

    for p, c in zip(parameter_comparison, COLORS):
        p.xscale = "log"
        p.plot(axs=axs, color=c)

plt.show()
plt.close()
/home/runner/work/NumCosmo/NumCosmo/numcosmo_py/ccl/comparison.py:144: UserWarning: Data has no positive values, and therefore cannot be log-scaled.
  axs[0].set_yscale(self.yscale)
Figure 1: Total matter density parameter
Figure 2: Radiation density parameter
Figure 3: Massless neutrino density parameter
Figure 4: Massive neutrino density parameter

The following table summarizes the results for all sets.

Code
table = []

for parameter_comparison in parameter_comparisons:
    for p in parameter_comparison:
        table.append(p.summary_row())

df = pd.DataFrame(table, columns=nc_cmp.CompareFunc1d.table_header())

display(Markdown(df.to_markdown(index=False, colalign=["left"] * len(df.columns))))
Model Quantity \(\Delta P_{\text{min}}/P\) \(\Delta P_{\text{max}}/P\) \(\overline{\Delta P / P}\) \(\sigma_{\Delta P / P}\)
\(\Lambda\)CDM, flat \(\Omega_m\) \(0\) \(7.8 \times 10^{-16}\) \(1.7 \times 10^{-16}\) \(1.3 \times 10^{-16}\)
\(\Lambda\)CDM, flat, \(1\nu\) \(\Omega_m\) \(1.1 \times 10^{-15}\) \(7.9 \times 10^{-10}\) \(7.1 \times 10^{-11}\) \(10^{-10}\)
XCDM, flat \(\Omega_m\) \(0\) \(8.9 \times 10^{-16}\) \(1.7 \times 10^{-16}\) \(1.4 \times 10^{-16}\)
XCDM, spherical, \(2\nu\) \(\Omega_m\) \(4 \times 10^{-15}\) \(5.2 \times 10^{-10}\) \(6.9 \times 10^{-11}\) \(8.6 \times 10^{-11}\)
XCDM, hyperbolic \(\Omega_m\) \(0\) \(8.9 \times 10^{-16}\) \(1.8 \times 10^{-16}\) \(1.5 \times 10^{-16}\)
\(\Lambda\)CDM, flat \(\Omega_g\) \(0\) \(10^{-15}\) \(2.3 \times 10^{-16}\) \(1.8 \times 10^{-16}\)
\(\Lambda\)CDM, flat, \(1\nu\) \(\Omega_g\) \(1.2 \times 10^{-14}\) \(3.2 \times 10^{-9}\) \(2 \times 10^{-10}\) \(2.2 \times 10^{-10}\)
XCDM, flat \(\Omega_g\) \(0\) \(1.1 \times 10^{-15}\) \(2.4 \times 10^{-16}\) \(1.9 \times 10^{-16}\)
XCDM, spherical, \(2\nu\) \(\Omega_g\) \(3.3 \times 10^{-15}\) \(3.5 \times 10^{-9}\) \(2.3 \times 10^{-10}\) \(3.4 \times 10^{-10}\)
XCDM, hyperbolic \(\Omega_g\) \(0\) \(1.2 \times 10^{-15}\) \(2.5 \times 10^{-16}\) \(1.9 \times 10^{-16}\)
\(\Lambda\)CDM, flat \(\Omega_{\nu}\) \(0\) \(8.9 \times 10^{-16}\) \(1.9 \times 10^{-16}\) \(1.6 \times 10^{-16}\)
\(\Lambda\)CDM, flat, \(1\nu\) \(\Omega_{\nu}\) \(1.2 \times 10^{-14}\) \(3.2 \times 10^{-9}\) \(2 \times 10^{-10}\) \(2.2 \times 10^{-10}\)
XCDM, flat \(\Omega_{\nu}\) \(0\) \(8.9 \times 10^{-16}\) \(2 \times 10^{-16}\) \(1.6 \times 10^{-16}\)
XCDM, spherical, \(2\nu\) \(\Omega_{\nu}\) \(3.6 \times 10^{-15}\) \(3.5 \times 10^{-9}\) \(2.3 \times 10^{-10}\) \(3.4 \times 10^{-10}\)
XCDM, hyperbolic \(\Omega_{\nu}\) \(0\) \(1.1 \times 10^{-15}\) \(2.1 \times 10^{-16}\) \(1.7 \times 10^{-16}\)
\(\Lambda\)CDM, flat \(\Omega_{m\nu}\) \(0\) \(0\) \(0\) \(0\)
\(\Lambda\)CDM, flat, \(1\nu\) \(\Omega_{m\nu}\) \(3.2 \times 10^{-12}\) \(2.7 \times 10^{-7}\) \(6.6 \times 10^{-8}\) \(4.3 \times 10^{-8}\)
XCDM, flat \(\Omega_{m\nu}\) \(0\) \(0\) \(0\) \(0\)
XCDM, spherical, \(2\nu\) \(\Omega_{m\nu}\) \(6.7 \times 10^{-12}\) \(2.3 \times 10^{-7}\) \(4.5 \times 10^{-8}\) \(3.3 \times 10^{-8}\)
XCDM, hyperbolic \(\Omega_{m\nu}\) \(0\) \(0\) \(0\) \(0\)
Table 2: Cosmological parameters computed using CCL and NumCosmo

Distances

We define a function to compare cosmological distances calculated by the CCL and NumCosmo frameworks. The function then evaluates and compares the cosmological distances implemented in both libraries. Expand the cell below to view the code.

distance_funcs = [
    nc_cmp.compare_Hubble,
    nc_cmp.compare_distance_comoving,
    nc_cmp.compare_distance_transverse,
    nc_cmp.compare_distance_angular_diameter,
    nc_cmp.compare_distance_luminosity,
    nc_cmp.compare_distance_modulus,
    nc_cmp.compare_distance_lookback_time,
    nc_cmp.compare_distance_comoving_volume,
]

distance_comparisons: list[list[nc_cmp.CompareFunc1d]] = [
    [func(m["CCL"], m["NC"], z, model=name) for m, name in zip(models, PARAMETERS_SET)]
    for func in distance_funcs
]

We plot the distance comparisons for all parameter sets.

Code
for distance_comparison in distance_comparisons:
    fig, axs = plt.subplots(2, sharex=True)
    fig.subplots_adjust(hspace=0)

    for d, c in zip(distance_comparison, COLORS):
        d.xscale = "log"
        d.plot(axs=axs, color=c)

plt.show()
plt.close()
Figure 5: Normalized Hubble Function
Figure 6: Comoving radial distance
Figure 7: Comoving transverse distance
Figure 8: Angular diameter distance
Figure 9: Luminosity distance
Figure 10: Distance modulus
Figure 11: Lookback time
Figure 12: Comoving volume element

Again a table summarizes the results for all parameter sets.

Code
table = []

for distance_comparison in distance_comparisons:
    for d in distance_comparison:
        table.append(d.summary_row())

df = pd.DataFrame(table, columns=nc_cmp.CompareFunc1d.table_header())

display(Markdown(df.to_markdown(index=False, colalign=["left"] * len(df.columns))))
Model Quantity \(\Delta P_{\text{min}}/P\) \(\Delta P_{\text{max}}/P\) \(\overline{\Delta P / P}\) \(\sigma_{\Delta P / P}\)
\(\Lambda\)CDM, flat \(H(z)/H_0\) \(3.2 \times 10^{-12}\) \(2.3 \times 10^{-5}\) \(2.5 \times 10^{-6}\) \(3.1 \times 10^{-6}\)
\(\Lambda\)CDM, flat, \(1\nu\) \(H(z)/H_0\) \(4.5 \times 10^{-12}\) \(2.3 \times 10^{-5}\) \(2.5 \times 10^{-6}\) \(3.1 \times 10^{-6}\)
XCDM, flat \(H(z)/H_0\) \(5.1 \times 10^{-13}\) \(2.3 \times 10^{-5}\) \(2.5 \times 10^{-6}\) \(3.1 \times 10^{-6}\)
XCDM, spherical, \(2\nu\) \(H(z)/H_0\) \(1.5 \times 10^{-11}\) \(2.2 \times 10^{-5}\) \(2.5 \times 10^{-6}\) \(3.1 \times 10^{-6}\)
XCDM, hyperbolic \(H(z)/H_0\) \(1.8 \times 10^{-12}\) \(2.3 \times 10^{-5}\) \(2.5 \times 10^{-6}\) \(3.1 \times 10^{-6}\)
\(\Lambda\)CDM, flat \(D_c\) [Mpc] \(5.8 \times 10^{-13}\) \(6.8 \times 10^{-7}\) \(4.5 \times 10^{-8}\) \(7.8 \times 10^{-8}\)
\(\Lambda\)CDM, flat, \(1\nu\) \(D_c\) [Mpc] \(2 \times 10^{-13}\) \(6.8 \times 10^{-7}\) \(4.5 \times 10^{-8}\) \(7.8 \times 10^{-8}\)
XCDM, flat \(D_c\) [Mpc] \(5.9 \times 10^{-13}\) \(7 \times 10^{-7}\) \(4.3 \times 10^{-8}\) \(7.3 \times 10^{-8}\)
XCDM, spherical, \(2\nu\) \(D_c\) [Mpc] \(1.2 \times 10^{-13}\) \(7.1 \times 10^{-7}\) \(4.2 \times 10^{-8}\) \(7.1 \times 10^{-8}\)
XCDM, hyperbolic \(D_c\) [Mpc] \(5.8 \times 10^{-13}\) \(6.8 \times 10^{-7}\) \(4.4 \times 10^{-8}\) \(7.5 \times 10^{-8}\)
\(\Lambda\)CDM, flat \(D_t\) [Mpc] \(5.8 \times 10^{-13}\) \(6.8 \times 10^{-7}\) \(4.5 \times 10^{-8}\) \(7.8 \times 10^{-8}\)
\(\Lambda\)CDM, flat, \(1\nu\) \(D_t\) [Mpc] \(2 \times 10^{-13}\) \(6.8 \times 10^{-7}\) \(4.5 \times 10^{-8}\) \(7.8 \times 10^{-8}\)
XCDM, flat \(D_t\) [Mpc] \(5.9 \times 10^{-13}\) \(7 \times 10^{-7}\) \(4.3 \times 10^{-8}\) \(7.3 \times 10^{-8}\)
XCDM, spherical, \(2\nu\) \(D_t\) [Mpc] \(1.3 \times 10^{-13}\) \(7.6 \times 10^{-7}\) \(4.3 \times 10^{-8}\) \(7.4 \times 10^{-8}\)
XCDM, hyperbolic \(D_t\) [Mpc] \(5 \times 10^{-13}\) \(6.3 \times 10^{-7}\) \(4.3 \times 10^{-8}\) \(7.3 \times 10^{-8}\)
\(\Lambda\)CDM, flat \(D_A\) [Mpc] \(5.8 \times 10^{-13}\) \(6.8 \times 10^{-7}\) \(4.5 \times 10^{-8}\) \(7.8 \times 10^{-8}\)
\(\Lambda\)CDM, flat, \(1\nu\) \(D_A\) [Mpc] \(2 \times 10^{-13}\) \(6.8 \times 10^{-7}\) \(4.5 \times 10^{-8}\) \(7.8 \times 10^{-8}\)
XCDM, flat \(D_A\) [Mpc] \(5.9 \times 10^{-13}\) \(7 \times 10^{-7}\) \(4.3 \times 10^{-8}\) \(7.3 \times 10^{-8}\)
XCDM, spherical, \(2\nu\) \(D_A\) [Mpc] \(1.3 \times 10^{-13}\) \(7.6 \times 10^{-7}\) \(4.3 \times 10^{-8}\) \(7.4 \times 10^{-8}\)
XCDM, hyperbolic \(D_A\) [Mpc] \(5 \times 10^{-13}\) \(6.3 \times 10^{-7}\) \(4.3 \times 10^{-8}\) \(7.3 \times 10^{-8}\)
\(\Lambda\)CDM, flat \(D_L\) [Mpc] \(5.8 \times 10^{-13}\) \(6.8 \times 10^{-7}\) \(4.5 \times 10^{-8}\) \(7.8 \times 10^{-8}\)
\(\Lambda\)CDM, flat, \(1\nu\) \(D_L\) [Mpc] \(2 \times 10^{-13}\) \(6.8 \times 10^{-7}\) \(4.5 \times 10^{-8}\) \(7.8 \times 10^{-8}\)
XCDM, flat \(D_L\) [Mpc] \(5.9 \times 10^{-13}\) \(7 \times 10^{-7}\) \(4.3 \times 10^{-8}\) \(7.3 \times 10^{-8}\)
XCDM, spherical, \(2\nu\) \(D_L\) [Mpc] \(1.3 \times 10^{-13}\) \(7.6 \times 10^{-7}\) \(4.3 \times 10^{-8}\) \(7.4 \times 10^{-8}\)
XCDM, hyperbolic \(D_L\) [Mpc] \(5 \times 10^{-13}\) \(6.3 \times 10^{-7}\) \(4.3 \times 10^{-8}\) \(7.3 \times 10^{-8}\)
\(\Lambda\)CDM, flat \(\mu\) \(2.3 \times 10^{-14}\) \(3 \times 10^{-8}\) \(2.5 \times 10^{-9}\) \(4.5 \times 10^{-9}\)
\(\Lambda\)CDM, flat, \(1\nu\) \(\mu\) \(9.8 \times 10^{-15}\) \(3 \times 10^{-8}\) \(2.5 \times 10^{-9}\) \(4.5 \times 10^{-9}\)
XCDM, flat \(\mu\) \(2.3 \times 10^{-14}\) \(3.1 \times 10^{-8}\) \(2.3 \times 10^{-9}\) \(4.1 \times 10^{-9}\)
XCDM, spherical, \(2\nu\) \(\mu\) \(5.6 \times 10^{-15}\) \(3.3 \times 10^{-8}\) \(2.3 \times 10^{-9}\) \(4 \times 10^{-9}\)
XCDM, hyperbolic \(\mu\) \(2 \times 10^{-14}\) \(2.8 \times 10^{-8}\) \(2.3 \times 10^{-9}\) \(4.2 \times 10^{-9}\)
\(\Lambda\)CDM, flat \(t_L\) [Gyr] \(1.4 \times 10^{-13}\) \(1.8 \times 10^{-7}\) \(5.5 \times 10^{-9}\) \(1.1 \times 10^{-8}\)
\(\Lambda\)CDM, flat, \(1\nu\) \(t_L\) [Gyr] \(1.3 \times 10^{-13}\) \(1.8 \times 10^{-7}\) \(5.5 \times 10^{-9}\) \(1.1 \times 10^{-8}\)
XCDM, flat \(t_L\) [Gyr] \(1.5 \times 10^{-13}\) \(1.8 \times 10^{-7}\) \(6.3 \times 10^{-9}\) \(1.2 \times 10^{-8}\)
XCDM, spherical, \(2\nu\) \(t_L\) [Gyr] \(1.3 \times 10^{-12}\) \(1.7 \times 10^{-7}\) \(6.8 \times 10^{-9}\) \(1.3 \times 10^{-8}\)
XCDM, hyperbolic \(t_L\) [Gyr] \(9.6 \times 10^{-13}\) \(1.8 \times 10^{-7}\) \(5.7 \times 10^{-9}\) \(1.2 \times 10^{-8}\)
\(\Lambda\)CDM, flat \(\mathrm{d}V/\mathrm{d}z\mathrm{d}\Omega\) [Mpc\({}^3\)] \(2.8 \times 10^{-11}\) \(2.2 \times 10^{-5}\) \(2.5 \times 10^{-6}\) \(3 \times 10^{-6}\)
\(\Lambda\)CDM, flat, \(1\nu\) \(\mathrm{d}V/\mathrm{d}z\mathrm{d}\Omega\) [Mpc\({}^3\)] \(3.5 \times 10^{-12}\) \(2.1 \times 10^{-5}\) \(2.5 \times 10^{-6}\) \(3 \times 10^{-6}\)
XCDM, flat \(\mathrm{d}V/\mathrm{d}z\mathrm{d}\Omega\) [Mpc\({}^3\)] \(2.5 \times 10^{-11}\) \(2.1 \times 10^{-5}\) \(2.5 \times 10^{-6}\) \(3 \times 10^{-6}\)
XCDM, spherical, \(2\nu\) \(\mathrm{d}V/\mathrm{d}z\mathrm{d}\Omega\) [Mpc\({}^3\)] \(7.9 \times 10^{-12}\) \(2.1 \times 10^{-5}\) \(2.5 \times 10^{-6}\) \(3 \times 10^{-6}\)
XCDM, hyperbolic \(\mathrm{d}V/\mathrm{d}z\mathrm{d}\Omega\) [Mpc\({}^3\)] \(1.8 \times 10^{-11}\) \(2.2 \times 10^{-5}\) \(2.5 \times 10^{-6}\) \(3.1 \times 10^{-6}\)
Table 3: Cosmological distances computed using CCL and NumCosmo

Time Comparison

We compare the time spent on calculating the cosmological distances. First, it is necessary to create again the cosmology used in the function, then we use “timeit” to estimate the mean time intervals it takes for each library to perform the calculations. Below we show the comparison using the first set of parameters.

Code
def compute_distance_times(
    ccl_cosmo: pyccl.Cosmology, cosmology: ncc.Cosmology, z: np.ndarray
):
    cosmo = cosmology.cosmo
    dist = cosmology.dist

    a = 1.0 / (1.0 + z)
    z_vec = Ncm.Vector.new_array(z)
    D_vec = z_vec.dup()
    table = [
        ["Comoving Distance", "CCL"]
        + nc_cmp.compute_times(lambda: pyccl.comoving_radial_distance(ccl_cosmo, a)),
        ["Comoving Distance", "NumCosmo"]
        + nc_cmp.compute_times(lambda: dist.comoving_vector(cosmo, z_vec, D_vec)),
        ["Transverse Distance", "CCL"]
        + nc_cmp.compute_times(lambda: pyccl.comoving_angular_distance(ccl_cosmo, a)),
        ["Transverse Distance", "NumCosmo"]
        + nc_cmp.compute_times(lambda: dist.transverse_vector(cosmo, z_vec, D_vec)),
        ["Angular Diameter Distance", "CCL"]
        + nc_cmp.compute_times(lambda: pyccl.angular_diameter_distance(ccl_cosmo, a)),
        ["Angular Diameter Distance", "NumCosmo"]
        + nc_cmp.compute_times(
            lambda: dist.angular_diameter_vector(cosmo, z_vec, D_vec)
        ),
        ["Luminosity Distance", "CCL"]
        + nc_cmp.compute_times(lambda: pyccl.luminosity_distance(ccl_cosmo, a)),
        ["Luminosity Distance", "NumCosmo"]
        + nc_cmp.compute_times(lambda: dist.luminosity_vector(cosmo, z_vec, D_vec)),
        ["Distance Modulus", "CCL"]
        + nc_cmp.compute_times(lambda: pyccl.distance_modulus(ccl_cosmo, a)),
        ["Distance Modulus", "NumCosmo"]
        + nc_cmp.compute_times(lambda: dist.dmodulus_vector(cosmo, z_vec, D_vec)),
    ]
    columns = ["Distance", "Library", "Mean Time", "Standard Deviation"]
    df = pd.DataFrame(table, columns=columns)

    df["Mean Time"] = df["Mean Time"].apply(format_time)
    df["Standard Deviation"] = df["Standard Deviation"].apply(format_time)
    return df


df = compute_distance_times(models[0]["CCL"], models[0]["NC"], z)

display(Markdown(df.to_markdown(index=False, colalign=["left"] * len(df.columns))))
Distance Library Mean Time Standard Deviation
Comoving Distance CCL 179.02 \(\mu\)s 17.62 \(\mu\)s
Comoving Distance NumCosmo 1.35 ms 1.43 \(\mu\)s
Transverse Distance CCL 232.56 \(\mu\)s 1.35 \(\mu\)s
Transverse Distance NumCosmo 1.36 ms 6.05 \(\mu\)s
Angular Diameter Distance CCL 350.41 \(\mu\)s 417.95 ns
Angular Diameter Distance NumCosmo 1.39 ms 47.96 \(\mu\)s
Luminosity Distance CCL 232.51 \(\mu\)s 1.45 \(\mu\)s
Luminosity Distance NumCosmo 1.36 ms 5.84 \(\mu\)s
Distance Modulus CCL 331.34 \(\mu\)s 1.05 \(\mu\)s
Distance Modulus NumCosmo 1.51 ms 2.05 \(\mu\)s
Table 4: Time to compute the cosmological distances

Growth Factor and Growth Rate

The following function compares the growth factor and growth rate between the CCL and NumCosmo cosmologies.

Since CCL defines \(\Omega_m\) differently from NumCosmo, the resulting growth factor and growth rate will also differ. In practice, CCL includes ultra-relativistic neutrinos in the matter density, leading to increasing deviations at higher redshifts when compared to NumCosmo. However, since we are using the CCL_comp mode of NumCosmo, we compute \(\Omega_m\) using the CCL prescription.

growth_funcs = [
    nc_cmp.compare_growth_factor,
    nc_cmp.compare_growth_rate,
]

growth_comparisons: list[list[nc_cmp.CompareFunc1d]] = [
    [func(m["CCL"], m["NC"], z, model=name) for m, name in zip(models, PARAMETERS_SET)]
    for func in growth_funcs
]    

Below we plot the growth comparisons for all parameter sets.

Code
for growth_comparison in growth_comparisons:
    fig, axs = plt.subplots(2, sharex=True)
    fig.subplots_adjust(hspace=0)

    for p, c in zip(growth_comparison, COLORS):
        p.xscale = "log"
        p.plot(axs=axs, color=c)

plt.show()
plt.close()
Figure 13: Growth Factor
Figure 14: Growth Rate

The following table summarizes the results for all sets.

Code
table = []

for growth_comparison in growth_comparisons:
    for d in growth_comparison:
        table.append(d.summary_row(convert_g=False))

df = pd.DataFrame(table, columns=nc_cmp.CompareFunc1d.table_header())
display(Markdown(df.to_markdown(index=False, colalign=["left"] * len(df.columns))))
Model Quantity \(\Delta P_{\text{min}}/P\) \(\Delta P_{\text{max}}/P\) \(\overline{\Delta P / P}\) \(\sigma_{\Delta P / P}\)
\(\Lambda\)CDM, flat \(D\) \(1.67 \times 10^{-11}\) \(1.61 \times 10^{-3}\) \(6.15 \times 10^{-5}\) \(2.17 \times 10^{-4}\)
\(\Lambda\)CDM, flat, \(1\nu\) \(D\) \(2.77 \times 10^{-11}\) \(3.79 \times 10^{-5}\) \(1.50 \times 10^{-6}\) \(4.82 \times 10^{-6}\)
XCDM, flat \(D\) \(4.92 \times 10^{-10}\) \(1.61 \times 10^{-3}\) \(6.15 \times 10^{-5}\) \(2.16 \times 10^{-4}\)
XCDM, spherical, \(2\nu\) \(D\) \(2.07 \times 10^{-12}\) \(2.27 \times 10^{-6}\) \(5.98 \times 10^{-7}\) \(6.17 \times 10^{-7}\)
XCDM, hyperbolic \(D\) \(1.26 \times 10^{-11}\) \(1.61 \times 10^{-3}\) \(6.15 \times 10^{-5}\) \(2.16 \times 10^{-4}\)
\(\Lambda\)CDM, flat \(f\) \(4.80 \times 10^{-10}\) \(4.22 \times 10^{-3}\) \(1.60 \times 10^{-4}\) \(5.63 \times 10^{-4}\)
\(\Lambda\)CDM, flat, \(1\nu\) \(f\) \(5.50 \times 10^{-11}\) \(1.02 \times 10^{-4}\) \(3.86 \times 10^{-6}\) \(1.35 \times 10^{-5}\)
XCDM, flat \(f\) \(1.02 \times 10^{-10}\) \(4.22 \times 10^{-3}\) \(1.60 \times 10^{-4}\) \(5.63 \times 10^{-4}\)
XCDM, spherical, \(2\nu\) \(f\) \(2.06 \times 10^{-11}\) \(1.13 \times 10^{-5}\) \(4.73 \times 10^{-7}\) \(1.49 \times 10^{-6}\)
XCDM, hyperbolic \(f\) \(1.24 \times 10^{-11}\) \(4.22 \times 10^{-3}\) \(1.60 \times 10^{-4}\) \(5.63 \times 10^{-4}\)
Table 5: Growth Factor and Growth Rate

Scale Factor

The next function will compare the scale factor calculated from a comoving distance \(\chi\) (in Mpc).

chi = np.geomspace(1.0e-2, 4.0e3, 1000)

compare_scale_factor: list[nc_cmp.CompareFunc1d] = [
    nc_cmp.compare_scale_factor(m["CCL"], m["NC"], chi, model=name)
    for m, name in zip(models, PARAMETERS_SET)
]    

Below we compare the scale factors for all parameter sets.

Code
fig, axs = plt.subplots(2, sharex=True)
fig.subplots_adjust(hspace=0)

for p, c in zip(compare_scale_factor, COLORS):
    p.plot(axs=axs, color=c)

plt.show()
plt.close()
Figure 15: Scale Factor

The following table summarizes the results for all sets.

Code
table = []

for d in compare_scale_factor:
    table.append(d.summary_row())

df = pd.DataFrame(table, columns=nc_cmp.CompareFunc1d.table_header())

display(Markdown(df.to_markdown(index=False, colalign=["left"] * len(df.columns))))
Model Quantity \(\Delta P_{\text{min}}/P\) \(\Delta P_{\text{max}}/P\) \(\overline{\Delta P / P}\) \(\sigma_{\Delta P / P}\)
\(\Lambda\)CDM, flat \(a\) \(4 \times 10^{-13}\) \(2.9 \times 10^{-10}\) \(1.1 \times 10^{-10}\) \(8.5 \times 10^{-11}\)
\(\Lambda\)CDM, flat, \(1\nu\) \(a\) \(9.1 \times 10^{-14}\) \(2.9 \times 10^{-10}\) \(1.1 \times 10^{-10}\) \(8.5 \times 10^{-11}\)
XCDM, flat \(a\) \(1.5 \times 10^{-13}\) \(2.5 \times 10^{-10}\) \(9.3 \times 10^{-11}\) \(7.3 \times 10^{-11}\)
XCDM, spherical, \(2\nu\) \(a\) \(5.9 \times 10^{-14}\) \(2.4 \times 10^{-10}\) \(8.8 \times 10^{-11}\) \(6.8 \times 10^{-11}\)
XCDM, hyperbolic \(a\) \(3.3 \times 10^{-13}\) \(2.6 \times 10^{-10}\) \(9.8 \times 10^{-11}\) \(7.7 \times 10^{-11}\)
Table 6: Scale Factor

Critical Surface Mass Density

The next function will compare the critical surface mass density.

zs = z = np.linspace(1.0, 5.0, 10000)
zl = 0.5

compare_sigmaC: list[nc_cmp.CompareFunc1d] = [
    nc_cmp.compare_Sigma_crit(m["CCL"], m["NC"], zs, zl, model=name)
    for m, name in zip(models, PARAMETERS_SET)
]

Below we compare the critical surface mass density for all parameter sets.

Code
fig, axs = plt.subplots(2, sharex=True)
fig.subplots_adjust(hspace=0)

for p, c in zip(compare_sigmaC, COLORS):
    p.plot(axs=axs, color=c)

plt.show()
plt.close()
Figure 16: Critical Surface Mass Density

The following table summarizes the results for all sets.

Code
table = []

for d in compare_sigmaC:
    table.append(d.summary_row())

df = pd.DataFrame(table, columns=nc_cmp.CompareFunc1d.table_header())

display(Markdown(df.to_markdown(index=False, colalign=["left"] * len(df.columns))))
Model Quantity \(\Delta P_{\text{min}}/P\) \(\Delta P_{\text{max}}/P\) \(\overline{\Delta P / P}\) \(\sigma_{\Delta P / P}\)
\(\Lambda\)CDM, flat \(\Sigma_\mathrm{crit}\) \(1.2 \times 10^{-12}\) \(4.1 \times 10^{-8}\) \(1.4 \times 10^{-8}\) \(9.7 \times 10^{-9}\)
\(\Lambda\)CDM, flat, \(1\nu\) \(\Sigma_\mathrm{crit}\) \(9.6 \times 10^{-13}\) \(4.1 \times 10^{-8}\) \(1.4 \times 10^{-8}\) \(9.7 \times 10^{-9}\)
XCDM, flat \(\Sigma_\mathrm{crit}\) \(8.5 \times 10^{-12}\) \(4.3 \times 10^{-8}\) \(1.4 \times 10^{-8}\) \(10^{-8}\)
XCDM, spherical, \(2\nu\) \(\Sigma_\mathrm{crit}\) \(4.7 \times 10^{-12}\) \(4.2 \times 10^{-8}\) \(1.5 \times 10^{-8}\) \(9.9 \times 10^{-9}\)
XCDM, hyperbolic \(\Sigma_\mathrm{crit}\) \(1.5 \times 10^{-12}\) \(4.3 \times 10^{-8}\) \(1.4 \times 10^{-8}\) \(10^{-8}\)
Table 7: Critical Surface Mass Density

Summary

In this notebook, we compared the cosmological results obtained using CCL and NumCosmo across several sections.

  • Cosmology Parameters: We examined the differences in the parameters, noting how the definitions of \(\Omega_m\) and the inclusion of massive neutrinos affect the results.
  • Distances: We compared cosmological distances and found strong agreement between CCL and NumCosmo.
    • Time Comparison: A detailed analysis of time measurements confirmed this consistency.
  • Growth Factor and Growth Rate: We highlighted the discrepancies in the growth factor and growth rate due to CCL’s inclusion of the full neutrino energy density, which leads to increased deviations at higher redshifts.
  • Scale Factor: The scale factor was also compared, showing similar trends across both methods.
  • Critical Surface Mass Density: We assessed this observable and observed agreement.

Overall, the results demonstrate good agreement between the two methods, with the main differences arising from CCL’s handling of neutrinos in the background model, particularly affecting growth-related observables at higher redshifts.