Hot New Early Dark Energy#

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import matplotlib.colors as mcolors

import classy as classy
##Define cosmologies:

dict_general = {
    # General & Background
    'h': 0.67810,
    'T_cmb': 2.7255,
    'omega_b': 0.02238280,
    'omega_cdm': 0.1201075,
    'N_ur': 3.044,
    'Omega_k': 0.,
    'YHe': 'BBN',
    'recombination': 'recfast',
    
    # Reionization
    'reio_parametrization': 'reio_camb',
    'z_reio': 7.6711,
    'reionization_exponent': 1.5,
    'reionization_width': 0.5,
    'helium_fullreio_redshift': 3.5,
    'helium_fullreio_width': 0.5,
    
    # Perturbations & Output types
    'output': 'tCl,pCl,lCl,mPk',
    'modes': 's',
    'ic': 'ad',
    'gauge': 'synchronous',
    'lensing': 'yes',
    
    # Primordial Spectrum
    'k_pivot': 0.05,
    'A_s': 2.100549e-09,
    'n_s': 0.9660499,
    'alpha_s': 0.,
    
    # Spectra Limits & LSS
    'l_max_scalars': 2500,
    'P_k_max_h/Mpc': 1.,
    'z_pk': 0,
    
    # Verbosity
    'input_verbose': 0,
    'background_verbose': 0,
    'thermodynamics_verbose': 0,
    'perturbations_verbose': 0,
    'transfer_verbose': 0,
    'primordial_verbose': 0,
    'lensing_verbose': 0,
    'output_verbose': 0,
    'back_integration_stepsize': 1e-3,
    'perturb_integration_stepsize': 1e-3
}



# Make some helper functions for cleaner code in the notebook:

def run_cosmo(classy_version, dict_in):
    model = classy_version.Class()
    model.set(dict_in)
    model.compute()
    return model

def plot_Cl_TT(model, ax = None,**kwargs):

    # Get the computed data dictionary
    cl = model.lensed_cl(2500)
    l = cl['ell']
    # Compute C_l = l(l+1)C_l / 2pi (in muK^2)
    factor = l * (l + 1) / (2 * np.pi) * 1e12
    cl_TT = factor * cl['tt']

    if ax is not None:
        ax.plot(l, cl_TT, **kwargs)

    return l, cl_TT

Running the Hot NEDE model in CLASS++:#

We can start by running the LCDM model as a baseline:

model_LCDM = run_cosmo(classy, {**dict_general})

To activate Hot NEDE in CLASS++, we need to tell CLASS++ to compute it with four parameters:

G_over_aH_drmd_ini,

delta_Neff_drmd,

f_idm_drmd,

z_stop.

dict_drmd={ 
        'G_over_aH_drmd_ini':1e5, # Interaction strength
        'delta_Neff_drmd':1.0, # Extra radiation from the DRMD component
        'f_idm_drmd':0.5, # Fraction of DM that is interacting
        'z_stop':500, # Redshift at which the interaction stops
}

model_Hot_NEDE = run_cosmo(classy, {**dict_general, **dict_drmd})

We can also extract some output values directly from classy:

print("Hot NEDE model outputs:")
print(f'Fraction of interacting dark radiation (compared to total energy density): f_idr_drmd = {model_Hot_NEDE.f_idr_drmd()}')
print(f'Redshift of decoupling: z_dec_drmd = {model_Hot_NEDE.z_dec_drmd()}')
Hot NEDE model outputs:
Fraction of interacting dark radiation (compared to total energy density): f_idr_drmd = 0.11838235723282768
Redshift of decoupling: z_dec_drmd = 51.83356067095277
N = 25
f_idm_drmds = np.linspace(0.01, 1.0, N)


fig, axs = plt.subplots(2,1, figsize=(10, 8), sharex=True, gridspec_kw={'height_ratios': [3, 1]})



# --- Colormap setup ---
# Restrict range to avoid very light colors
def truncate_cmap(cmap, minval=0.3, maxval=0.9, n=100):
    return mcolors.LinearSegmentedColormap.from_list(
        f'trunc({cmap.name})',
        cmap(np.linspace(minval, maxval, n))
    )

cmap_drmd = truncate_cmap(cm.Reds)
cmap_ratio = truncate_cmap(cm.cool)

norm = mcolors.Normalize(vmin=0, vmax=1)


ls_LCDM, cls_LCDM = plot_Cl_TT(model_LCDM, ax=axs[0], label=r'$\Lambda$CDM', color='black')
for f_idm_drmd in f_idm_drmds:
    dict_drmd_local = {**dict_general, **dict_drmd, 'f_idm_drmd': f_idm_drmd}


    model_drmd_local = classy.Class()
    model_drmd_local.set(dict_drmd_local)
    model_drmd_local.compute()

    color_drmd = cmap_drmd(norm(f_idm_drmd))
    color_ratio = cmap_ratio(norm(f_idm_drmd))


    ls_drmd, cls_drmd = plot_Cl_TT(
        model_drmd_local, axs[0],
        color=color_drmd,
        alpha = 0.7
    )


    axs[1].plot(
        ls_drmd,
        (cls_drmd / cls_LCDM - 1) * 100,
        color=color_ratio
    )


axs[1].axhline(0, color='black', linestyle='--', alpha=0.7)

# --- Colorbars ---
sm_drmd = cm.ScalarMappable(cmap=cmap_drmd, norm=norm)
sm_drmd.set_array([])
cbar_drmd = fig.colorbar(sm_drmd, ax=axs[0])
cbar_drmd.set_label(r'$f_{\mathrm{idm\_drmd}}$')



sm_ratio = cm.ScalarMappable(cmap=cmap_ratio, norm=norm)
sm_ratio.set_array([])
cbar_ratio = fig.colorbar(sm_ratio, ax=axs[1])
cbar_ratio.set_label(r'$f_{\mathrm{idm\_drmd}}$')


# -------Axes labels and titles-------
axs[0].set_xlabel(r'Multipole $\ell$')
axs[0].set_ylabel(r'$C_\ell^{TT}$ [$\mu K^2$]')
axs[0].set_title('CMB Temperature Power Spectrum')
axs[0].legend()

axs[1].set_xlabel(r'Multipole $\ell$')
axs[1].set_ylabel(r'$\Delta C_\ell^{TT}$ [%]')
axs[1].set_title('Relative Difference to $\Lambda$CDM')
/tmp/ipykernel_3533832/2963136698.py:44: RuntimeWarning: invalid value encountered in divide
  (cls_drmd / cls_LCDM - 1) * 100,
Text(0.5, 1.0, 'Relative Difference to $\\Lambda$CDM')
../_images/f8cebc7f0e7f11f4a2a38b3a0e111651951cff3d5597fae7c057fa5870fb13a5.png
G_over_aH_drmd_inis = np.logspace(-9, 15, N)


fig, axs = plt.subplots(2,1, figsize=(10, 8), sharex=True, gridspec_kw={'height_ratios': [3, 1]})



# --- Colormap setup ---
# Restrict range to avoid very light colors
def truncate_cmap(cmap, minval=0.3, maxval=0.9, n=100):
    return mcolors.LinearSegmentedColormap.from_list(
        f'trunc({cmap.name})',
        cmap(np.linspace(minval, maxval, n))
    )

cmap_drmd = truncate_cmap(cm.Reds)
cmap_ratio = truncate_cmap(cm.cool)

norm = mcolors.LogNorm(vmin=G_over_aH_drmd_inis.min(), vmax=G_over_aH_drmd_inis.max())

ls_LCDM, cls_LCDM = plot_Cl_TT(model_LCDM, ax=axs[0], label=r'$\Lambda$CDM', color='black')
for G_over_aH_drmd_ini in G_over_aH_drmd_inis:
    dict_drmd_local = {**dict_general, **dict_drmd, 'G_over_aH_drmd_ini': G_over_aH_drmd_ini}


    model_drmd_local = classy.Class()
    model_drmd_local.set(dict_drmd_local)
    model_drmd_local.compute()

    color_drmd = cmap_drmd(norm(G_over_aH_drmd_ini))
    color_ratio = cmap_ratio(norm(G_over_aH_drmd_ini))


    ls_drmd, cls_drmd = plot_Cl_TT(
        model_drmd_local, axs[0],
        color=color_drmd,
        alpha = 0.7
    )


    axs[1].plot(
        ls_drmd,
        (cls_drmd / cls_LCDM - 1) * 100,
        color=color_ratio
    )


axs[1].axhline(0, color='black', linestyle='--', alpha=0.7)

# --- Colorbars ---
sm_drmd = cm.ScalarMappable(cmap=cmap_drmd, norm=norm)
sm_drmd.set_array([])
cbar_drmd = fig.colorbar(sm_drmd, ax=axs[0])
cbar_drmd.set_label(r'$f_{\mathrm{idm\_drmd}}$')



sm_ratio = cm.ScalarMappable(cmap=cmap_ratio, norm=norm)
sm_ratio.set_array([])
cbar_ratio = fig.colorbar(sm_ratio, ax=axs[1])
cbar_ratio.set_label(r'$G/aH_{\mathrm{idm\_drmd}}$')


# -------Axes labels and titles-------
axs[0].set_xlabel(r'Multipole $\ell$')
axs[0].set_ylabel(r'$C_\ell^{TT}$ [$\mu K^2$]')
axs[0].set_title('CMB Temperature Power Spectrum')
axs[0].legend()

axs[1].set_xlabel(r'Multipole $\ell$')
axs[1].set_ylabel(r'$\Delta C_\ell^{TT}$ [%]')
axs[1].set_title('Relative Difference to $\Lambda$CDM')
/tmp/ipykernel_3533832/790192118.py:43: RuntimeWarning: invalid value encountered in divide
  (cls_drmd / cls_LCDM - 1) * 100,
Text(0.5, 1.0, 'Relative Difference to $\\Lambda$CDM')
../_images/600e29a61b8599c2fdf5f83dee55a5becd75885d276881b4e42206ddc1345b23.png
z_stops = np.logspace(2, 5, N)


fig, axs = plt.subplots(2,1, figsize=(10, 8), sharex=True, gridspec_kw={'height_ratios': [3, 1]})



# --- Colormap setup ---
# Restrict range to avoid very light colors
def truncate_cmap(cmap, minval=0.3, maxval=0.9, n=100):
    return mcolors.LinearSegmentedColormap.from_list(
        f'trunc({cmap.name})',
        cmap(np.linspace(minval, maxval, n))
    )

cmap_drmd = truncate_cmap(cm.Reds)
cmap_ratio = truncate_cmap(cm.cool)

norm = mcolors.LogNorm(vmin=z_stops.min(), vmax=z_stops.max())


ls_LCDM, cls_LCDM = plot_Cl_TT(model_LCDM, ax=axs[0], label=r'$\Lambda$CDM', color='black')
for z_stop in z_stops:
    dict_drmd_local = {**dict_general, **dict_drmd, 'z_stop': z_stop}


    model_drmd_local = classy.Class()
    model_drmd_local.set(dict_drmd_local)
    model_drmd_local.compute()

    color_drmd = cmap_drmd(norm(z_stop))
    color_ratio = cmap_ratio(norm(z_stop))


    ls_drmd, cls_drmd = plot_Cl_TT(
        model_drmd_local, axs[0],
        color=color_drmd,
        alpha = 0.7
    )


    axs[1].plot(
        ls_drmd,
        (cls_drmd / cls_LCDM - 1) * 100,
        color=color_ratio
    )


axs[1].axhline(0, color='black', linestyle='--', alpha=0.7)

# --- Colorbars ---
sm_drmd = cm.ScalarMappable(cmap=cmap_drmd, norm=norm)
sm_drmd.set_array([])
cbar_drmd = fig.colorbar(sm_drmd, ax=axs[0])
cbar_drmd.set_label(r'$z_{\mathrm{stop}}$')



sm_ratio = cm.ScalarMappable(cmap=cmap_ratio, norm=norm)
sm_ratio.set_array([])
cbar_ratio = fig.colorbar(sm_ratio, ax=axs[1])
cbar_ratio.set_label(r'$z_{\mathrm{stop}}$')


# -------Axes labels and titles-------
axs[0].set_xlabel(r'Multipole $\ell$')
axs[0].set_ylabel(r'$C_\ell^{TT}$ [$\mu K^2$]')
axs[0].set_title('CMB Temperature Power Spectrum')
axs[0].legend()

axs[1].set_xlabel(r'Multipole $\ell$')
axs[1].set_ylabel(r'$\Delta C_\ell^{TT}$ [%]')
axs[1].set_title('Relative Difference to $\Lambda$CDM')
/tmp/ipykernel_3533832/3368307376.py:44: RuntimeWarning: invalid value encountered in divide
  (cls_drmd / cls_LCDM - 1) * 100,
Text(0.5, 1.0, 'Relative Difference to $\\Lambda$CDM')
../_images/45169f1f03f16243edac69c4a6cc0a93bc92dc3c4be7e54772e70c63c4dc6866.png
delta_Neff_drmds = np.linspace(0.1,3, N)


fig, axs = plt.subplots(2,1, figsize=(10, 8), sharex=True, gridspec_kw={'height_ratios': [3, 1]})



# --- Colormap setup ---
# Restrict range to avoid very light colors
def truncate_cmap(cmap, minval=0.3, maxval=0.9, n=100):
    return mcolors.LinearSegmentedColormap.from_list(
        f'trunc({cmap.name})',
        cmap(np.linspace(minval, maxval, n))
    )

cmap_drmd = truncate_cmap(cm.Reds)
cmap_ratio = truncate_cmap(cm.cool)

norm = mcolors.Normalize(vmin=0, vmax=1)

ls_LCDM, cls_LCDM = plot_Cl_TT(model_LCDM, ax=axs[0], label=r'$\Lambda$CDM', color='black')
for delta_Neff_drmd in delta_Neff_drmds:
    dict_drmd_local = {**dict_general, **dict_drmd, 'delta_Neff_drmd': delta_Neff_drmd}


    model_drmd_local = classy.Class()
    model_drmd_local.set(dict_drmd_local)
    model_drmd_local.compute()

    color_drmd = cmap_drmd(norm(delta_Neff_drmd))
    color_ratio = cmap_ratio(norm(delta_Neff_drmd))


    ls_drmd, cls_drmd = plot_Cl_TT(
        model_drmd_local, axs[0],
        color=color_drmd,
        alpha = 0.7,
        label = ''
    )


    axs[1].plot(
        ls_drmd,
        (cls_drmd / cls_LCDM - 1) * 100,
        color=color_ratio
    )

axs[1].axhline(0, color='black', linestyle='--', alpha=0.7)

# --- Colorbars ---
sm_drmd = cm.ScalarMappable(cmap=cmap_drmd, norm=norm)
sm_drmd.set_array([])
cbar_drmd = fig.colorbar(sm_drmd, ax=axs[0])
cbar_drmd.set_label(r'$\Delta N_{\mathrm{eff}}^{\mathrm{drmd}}$')



sm_ratio = cm.ScalarMappable(cmap=cmap_ratio, norm=norm)
sm_ratio.set_array([])
cbar_ratio = fig.colorbar(sm_ratio, ax=axs[1])
cbar_ratio.set_label(r'$\Delta N_{\mathrm{eff}}^{\mathrm{drmd}}$')


# -------Axes labels and titles-------
axs[0].set_xlabel(r'Multipole $\ell$')
axs[0].set_ylabel(r'$C_\ell^{TT}$ [$\mu K^2$]')
axs[0].set_title('CMB Temperature Power Spectrum')
axs[0].legend()

axs[1].set_xlabel(r'Multipole $\ell$')
axs[1].set_ylabel(r'$\Delta C_\ell^{TT}$ [%]')
axs[1].set_title('Relative Difference to $\Lambda$CDM')
/tmp/ipykernel_3533832/586358244.py:44: RuntimeWarning: invalid value encountered in divide
  (cls_drmd / cls_LCDM - 1) * 100,
Text(0.5, 1.0, 'Relative Difference to $\\Lambda$CDM')
../_images/d2790fc32a277f9cd3209c06172352509b13e19e65f1c0c570b4ce1ef7f6e611.png