Background cosmology and species

The homogeneous universe in Cosmic.jl is a Cosmology: a container of species, each knowing its own energy density $\rho(a)/\rho_{c,0}$ and equation of state $w(a)$. The Friedmann equation is then just the sum

\[\frac{H^2(a)}{H_0^2} = \sum_i \frac{\rho_i(a)}{\rho_{c,0}},\]

and every background quantity — distances, ages, horizons — is an integral over it. Nothing assumes a particular species content, so exotic components (warm or decaying dark matter, quintessence) enter on exactly the same footing as photons and baryons.

Building a cosmology

cosmology() assembles the species from familiar parameters. Two choices are worth spelling out. First, the helium fraction defaults to Yp = :bbn: given $\omega_b$ and $N_{\rm eff}$, nucleosynthesis fixes $Y_p$, so treating it as a free parameter would let a model quietly carry a helium abundance inconsistent with its own baryon density; the network is solved (and cached) instead. Second, dark energy closes the budget: $\Omega_{\rm DE}$ is never an input but whatever flatness (or the requested $\Omega_k$) demands.

Massive neutrinos are never approximated by a power law in $a$. Their density comes from the exact phase-space integral $\rho \propto \int dq\, q^2 \sqrt{q^2 + (ma/T_{\nu,0})^2}\, f_0(q)$, which crosses from radiation-like to matter-like behaviour with no interpolation.

Dark energy

Four options, in increasing generality:

  • a cosmological constant (the default, w0 = -1, wa = 0);
  • the CPL fluid w(a) = w0 + wa (1 - a);
  • an arbitrary w_func(a), whose density integrates the continuity equation numerically;
  • a quintessence field: pass a potential V_scf (in units of the critical density, with the field in reduced Planck masses) and its derivative dV_scf. The Klein–Gordon equation is solved through the full expansion history, with the potential amplitude shot by bisection so the field's density today closes the budget exactly. The field starts frozen — the early-time attractor under Hubble friction — and its $w(a)$ is whatever the potential produces, not a parameterization.

For anything other than the cosmological constant, the corresponding perturbations are evolved automatically (see Linear perturbations); a true $\Lambda$ carries none, exactly.

Dark matter beyond CDM

Warm dark matter (cosmology(m_wdm = ..., Ω_wdm = ...)) is a thermal fermion relic riding the same momentum-resolved machinery as massive neutrinos. Its temperature ratio to the neutrinos follows from the abundance through the exact phase-space integral rather than the usual $93.14\,\mathrm{eV}$ shortcut (which assumes instantaneous-decoupling neutrino temperature and is about 1% off). The free-streaming suppression of structure it produces is computed, not fitted; the resulting cutoff reproduces the Viel transfer function at the few-percent level as an output.

Decaying dark matter (Γ_dcdm in km/s/Mpc, Ω_dcdm_ini the abundance it would have today without decay) converts to a dark radiation component through $\dot\rho_{\rm dcdm} = -3\mathcal{H}\rho_{\rm dcdm} - a\Gamma\rho_{\rm dcdm}$. No closed form exists — the decay is in proper time, so the history depends on the expansion it modifies — and the coupled system is solved at construction, self-consistently with the dark-energy closure. The realised $\Omega_{\rm dcdm}$ today matches the analytic $\Omega_{\rm ini} e^{-\Gamma t_0}$ to five digits, and the full perturbation sector (including the sourced dark-radiation hierarchy) reproduces the decay response of CLASS to better than half a percent in the CMB.

Annihilating dark matter affects the thermal history rather than the background; see Thermal history.

Distances and times

The usual kinematic toolbox — comoving, transverse comoving, angular-diameter and luminosity distances, lookback time, age, conformal time — all as direct integrals over $E(a)$ with curvature handled exactly in open, flat, and closed geometries.

Reference

Cosmic.CosmologyType
Cosmology

Container for a background model. Build one with cosmology rather than calling this constructor directly.

Fields beyond the species list:

  • h : H0 = 100h km/s/Mpc
  • Tcmb : CMB temperature today, K
  • Yp : primordial helium mass fraction (needed by recombination)
  • A_s,n_s,k_pivot : primordial curvature power spectrum, PR(k) = As (k/kpivot)^(ns - 1)
source
Cosmic.EMethod
E(c, a)

Dimensionless expansion rate H(a)/H0, from summing every species:

E(a)² = Σ_s ρ_s(a)/ρ_c0
source
Cosmic.E_zMethod

H(a)/H0 as a function of redshift instead of scale factor.

source
Cosmic.H_MpcMethod

Hubble rate in 1/Mpc (the internal unit), as a function of scale factor.

source
Cosmic.ageFunction
age(c, z; unit = :Gyr)

Age of the universe at redshift z: t = ∫₀^a da/(a H(a)).

source
Cosmic.angular_diameter_distanceMethod
angular_diameter_distance(c, z₁, z₂)

Angular-diameter distance between two redshifts, the quantity gravitational lensing needs. Note this is not DA(z₂) - DA(z₁); the curvature-correct form (Hogg 1999 eq. 19) is used.

source
Cosmic.comoving_distanceMethod
comoving_distance(c, z₁, z₂ = nothing)

Line-of-sight comoving distance in Mpc. With one redshift, the distance from us to z₁; with two, the distance between them.

source
Cosmic.comoving_volumeMethod
comoving_volume(c, z)

All-sky comoving volume out to z, in Mpc³, with the curvature correction (Hogg 1999 eq. 29).

source
Cosmic.conformal_timeMethod
conformal_time(c, a)

Conformal time η = ∫₀^a da'/(a'² H(a')), in Mpc. This is the time variable the Boltzmann hierarchy is integrated in, and it doubles as the comoving particle horizon.

source
Cosmic.cosmologyMethod
cosmology(; h, Ω_b, Ω_c, Ω_k, Tcmb, N_eff, m_ν, w0, wa, ...)

Build a Cosmology. Defaults are Planck 2018 TT,TE,EE+lowE+lensing+BAO.

Dark energy closes the budget: Ωde = 1 - Ωk - Σ(everything else), evaluated today so that massive neutrinos (which are matter now but were radiation once) are counted correctly.

Neutrinos: m_ν is a vector of masses in eV. Species with mass are given the full phase-space treatment; the remainder of N_eff is carried by massless species. The default m_ν = [0.06, 0.0, 0.0] is the minimal normal hierarchy. Pass m_ν = Float64[] for the (unphysical, but common in older codes) case of three massless neutrinos. Vectors shorter than three are zero-padded under the standard active-neutrino convention. Set N_ν_slots explicitly for a different number of slots. ξ_ν sets mass-slot degeneracies; ξ_νe separately sets the electron-flavour degeneracy entering BBN weak rates. When every slot has the same ξ, ξ_νe is inferred from it.

Dark energy: w0/wa select CPL. For anything more exotic, pass w_func, an arbitrary function of a.

Examples

c = cosmology()                              # Planck 2018 ΛCDM
c = cosmology(Ω_k = 0.01)                    # open
c = cosmology(w0 = -0.9, wa = -0.3)          # CPL dark energy
c = cosmology(m_ν = [0.1, 0.1, 0.1])         # degenerate 0.3 eV neutrinos
c = cosmology(w_func = a -> -1 + 0.1*(1-a)^2)  # arbitrary w(a)
source
Cosmic.get_speciesMethod
get_species(c, Type)

Return the first species of the given type, or nothing. Used by the thermodynamics and perturbation layers, which need e.g. the baryons specifically rather than just the total density.

source
Cosmic.scale_factor_of_timeMethod
scale_factor_of_time(c, t_Gyr)

Invert t(a) to get a(t). Replaces the old ODE-based scale_fact, which integrated da/dt from a = 1e-8 and inherited whatever error that seeding introduced; root-solving the age integral is both faster and exact.

source
Cosmic.transverse_comoving_distanceMethod
transverse_comoving_distance(c, z)

Comoving distance transverse to the line of sight, DM. This is where spatial curvature finally shows up: for Ωk ≠ 0 a comoving separation subtends a different angle than it would in flat space, so

D_M = D_H/√Ω_k  · sinh(√Ω_k · D_C/D_H)     (open,   Ω_k > 0)
D_M = D_C                                   (flat,   Ω_k = 0)
D_M = D_H/√|Ω_k| · sin (√|Ω_k| · D_C/D_H)   (closed, Ω_k < 0)

Angular-diameter and luminosity distances are built on DM, not DC, which is the piece the old code was missing.

source
Cosmic.z_equalityMethod
z_equality(c)

Redshift of matter-radiation equality, from root-solving ρm(a) = ρr(a).

source
Cosmic.Ω_rMethod

Radiation density today (the relativistic share 3P of every species).

source
Cosmic.ρ_matterMethod
ρ_matter(c, a), ρ_radiation(c, a)

Non-relativistic and relativistic energy densities, in units of ρ_c0.

For a species with density ρ and pressure P, CLASS separates the relativistic share as 3P and the non-relativistic share as ρ−3P. This is exact in both limits and remains continuous through the massive-neutrino transition. Decaying CDM and its daughter radiation are assigned to their physical sectors.

source
Cosmic.BaryonsType
Baryons(Ω_b)

Baryonic matter. Dynamically identical to CDM in the background (ρ ∝ a⁻³) but tracked separately: it is tightly coupled to the photons before recombination, and the thermodynamics and perturbation layers need Ω_b on its own.

source
Cosmic.CurvatureType
Curvature(Ω_k)

Not a fluid, but it enters E(a)² the same way, with ρeff ∝ a⁻². Sign convention: Ωk > 0 is an open (negatively curved) universe.

source
Cosmic.DecayingCDMType
DecayingCDM(Γ, lnρ) / DecayRadiation(lnρ)

Cold dark matter decaying into a relativistic dark radiation with rate Γ (in 1/Mpc, per proper time). Unlike every other species these have no closed-form density: ρ_dcdm ∝ a⁻³ e^{−Γt} needs t(a), which depends on the full expansion history — including the decay products themselves. cosmology() therefore solves the coupled system

d ln ρ_dcdm/dx = −3 − aΓ/ℋ
d ln ρ_dr/dx   = −4 + (aΓ/ℋ) ρ_dcdm/ρ_dr,      x = ln a, ℋ = aH,

self-consistently (fixed-point in the dark-energy closure) and stores the two histories as interpolants carried by this species pair.

source
Cosmic.FermiDiracType
FermiDirac(ξ = 0)

Pair-averaged neutrino plus antineutrino Fermi–Dirac distribution

f₀(q) = 1/2 [1/(e^{q−ξ}+1) + 1/(e^{q+ξ}+1)]

with degeneracy parameter ξ = μ/T. The antineutrino chemical potential is −μ, so this is the distribution whose energy integral obeys the standard exact even-in-ξ density enhancement. ξ = 0 is the standard case.

source
Cosmic.GeneralDarkEnergyType
GeneralDarkEnergy(Ω_de, w_func)

Dark energy with an arbitrary equation of state w_func(a). The density comes from integrating the continuity equation numerically,

ρ(a)/ρ₀ = exp( 3 ∫_a^1 [1 + w(a')] da'/a' )

which is slower than the closed forms above but imposes no restriction on the shape of w(a) – early dark energy, quintessence tracker fields, oscillating models all just work.

source
Cosmic.MassiveNeutrinosType
MassiveNeutrinos(Ω_rel, y1)

One massive neutrino species. Ω_rel is the density parameter it would have if it stayed massless, and y1 = m c²/(k T_ν,0) is its mass in units of the neutrino temperature today.

Density and pressure follow from the phase-space integral:

ρ(a)/ρ_c0 = Ω_rel · F(y1·a) / F(0) / a⁴

The species behaves as radiation while y1·a ≪ 1 and as matter once y1·a ≫ 1, with the transition handled exactly rather than by interpolating between two power laws.

source
Cosmic.MasslessNeutrinosType
MasslessNeutrinos(Ω_ν)

A relativistic neutrino background, or any other relativistic relic. ρ ∝ a⁻⁴.

The standard normalisation for N effectively-massless species is Ων = N · (7/8) · (4/11)^(4/3) · Ωγ, which massless_neutrinos applies for you.

source
Cosmic.NeutrinoDistributionType
NeutrinoDistribution

The momentum distribution f₀(q) (q = p/Tν in units of the present neutrino temperature) that a neutrino species is born with. The default is a Fermi–Dirac gas; a nonzero degeneracy parameter ξ = μ/T encodes a lepton asymmetry, and TabulatedNu carries an arbitrary numerically-specified f₀. Everything downstream — the background ρ, p and the free-streaming perturbation hierarchy — is built from `nuf0andnu_dlnf0`, so the distribution enters the physics in exactly one place.

source
Cosmic.QuintessenceDEType
QuintessenceDE(Ω, lnρ, w_itp)

Dark energy from a canonical scalar field rolling in a potential V(φ). The background Klein–Gordon equation is solved in cosmology() (with the potential amplitude shot to close the budget) and the resulting ρ(a), w(a) histories are carried here as interpolants in x = ln a.

Perturbations come for free and exactly: a canonical scalar field is precisely a fluid with rest-frame sound speed ĉs² = 1 (e.g. arXiv:1004.5509 §2), so the validated fld machinery in perturbations.jl — which picks up any non-Λ AbstractDarkEnergy with cs2de = 1 by default — evolves the exact quintessence perturbations with no Klein–Gordon perturbation block needed.

source
Cosmic.TabulatedNuType
TabulatedNu(f0, dlnf0)

Arbitrary neutrino distribution given by callables f0(q) and its logarithmic derivative dlnf0(q) = dln f₀/dln q (non-thermal relics, sterile mixtures, …).

source
Cosmic.W0WaDarkEnergyType
W0WaDarkEnergy(Ω_de, w0, wa)

CPL / Chevallier-Polarski-Linder parameterisation, w(a) = w0 + wa(1 - a). Integrating the continuity equation gives

ρ(a)/ρ₀ = a^(-3(1 + w0 + wa)) · exp(-3 wa (1 - a))
source
Cosmic.degenerate_Neff_factorMethod
degenerate_Neff_factor(ξ)

Radiation-density enhancement of a degenerate neutrino relative to ξ = 0, ρν(ξ)/ρν(0) = 1 + (30/7)(ξ/π)² + (15/7)(ξ/π)⁴ (exact for Fermi–Dirac). A single non-zero ξ therefore adds ΔN_eff = (this − 1) per affected species.

source
Cosmic.massive_neutrinoMethod
massive_neutrino(m_eV, Tcmb, h; N_eff_share = 1.0, ξ = 0, dist = nothing)

Build a massive neutrino species of mass m_eV.

N_eff_share is how much of Neff this species carries (1.0 for one of three standard neutrinos). It rescales the effective temperature by `Neffshare^(1/4)`, folding the non-instantaneous decoupling correction (Neff = 3.044, not 3) into a per-species temperature.

ξ is a degeneracy parameter (μ/T, a lepton asymmetry): it uses a FermiDirac(ξ) distribution and enhances the relativistic density by degenerate_Neff_factor(ξ). Pass a custom TabulatedNu as dist for a fully arbitrary phase space (then ξ is ignored).

source
Cosmic.nu_ρ_integralFunction
nu_ρ_integral(y, dist = FermiDirac())

The dimensionless energy integral

F(y) = ∫₀^∞ dx  x² √(x² + y²) f₀(x),     y = m c² / kT_ν(a),

which controls how a massive neutrino's density evolves. For Fermi–Dirac with ξ = 0, F(0) = 7π⁴/120 ≈ 5.6822 (relativistic, ρ ∝ a⁻⁴) and F(y→∞) → y·(3/2)ζ(3) (ρ → m·n, ρ ∝ a⁻³). Neutrinos are the one component that crosses between the two, so no ρ ∝ a⁻ⁿ power law describes them. A generic dist (degenerate or tabulated) just replaces f₀.

source
Cosmic.wFunction
w(s::Species, a)

Equation-of-state parameter P/ρ.

source
Cosmic.warm_dark_matterMethod
warm_dark_matter(m_keV, Ω_wdm, Tcmb, h)

A thermal warm-dark-matter relic: a fermion that froze out relativistic with two degrees of freedom at its own temperature Tw < Tν, cool enough to be all of (or part of) the dark matter today, warm enough that its residual free streaming erases small-scale structure. Exactly the same phase-space physics as a massive neutrino — the full momentum-resolved Boltzmann hierarchy — with the temperature ratio β = Tw/Tν fixed by the abundance:

Ω_wdm h² = β³ · m / (93.14 eV)    ⇒    β = (Ω_wdm h² · 93.14 eV / m)^{1/3},

the standard thermal-relic normalisation (the same one CLASS uses for its T_ncdm). Momenta are measured in units of Tw,0, so the distribution is a clean Fermi–Dirac and `y1 = m/Tw,0`; the relativistic density scales as β⁴.

The free-streaming cutoff this produces can be cross-checked against the Bode/Viel transfer-function fits — but here it is computed, not fitted.

source
Cosmic.ρ_over_ρc0Function
ρ_over_ρc0(s::Species, a)

Energy density of s at scale factor a, in units of the critical density today. Every species must implement this.

source