Observable quantities

This page shows observable quantities that can be derived from solutions of the Einstein-Boltzmann system, such as power spectra and distances.

Primordial power spectra

SymBoltz.spectrum_primordialFunction
spectrum_primordial(k, h, As, ns=1.0; kp = 0.05/u"Mpc")

Compute the primordial power spectrum

\[P₀(k) = 2π² Aₛ (k/kₚ)^{nₛ-1} / k³\]

with spectral amplitude As, spectral index ns and pivot scale wavenumber kp at the wavenumber(s) k.

source

Example

using SymBoltz, Unitful, UnitfulAstro, Plots
M = SymBoltz.ΛCDM()
pars = Dict(M.g.h => 0.7, M.I.As => 2e-9, M.I.ns => 0.95)
ks = 10 .^ range(-5, +1, length=100) / u"Mpc"
Ps = spectrum_primordial(ks, M, pars)
plot(log10.(ks*u"Mpc"), log10.(Ps/u"Mpc^3"); xlabel = "log10(k/Mpc⁻¹)", ylabel = "log10(P/Mpc³)")
Example block output

Matter power spectra

SymBoltz.spectrum_matterFunction
spectrum_matter(sol::CosmologySolution, k, τ = sol[τ][end]; species = [:c, :b, :h])

Compute the power spectrum

\[P(k,τ) = P₀(k) |Δ(k,τ)|²\]

of the total gauge-invariant overdensity

\[Δ = δ + (3ℋ/k²) θ = (∑ₛδρ)/(∑ₛρₛ) + (3ℋ/k²) (∑ₛ(ρₛ+Pₛ)θₛ) / (∑ₛ(ρₛ+Pₛ))\]

for the given species at wavenumber(s) k and conformal time(s) tau (final, if omitted) from the solution sol. By default, the species are cold dark matter, baryons and massive neutrinos, which are matter-like at late times in the ΛCDM model.

source
spectrum_matter(prob::CosmologyProblem, k, τ = nothing; species = [:c, :b, :h], kwargs...)

Solve the problem prob with exact wavenumber(s) k, and then compute the power spectrum with the solution sol.

source
SymBoltz.spectrum_matter_nonlinearFunction
spectrum_matter_nonlinear(sol::CosmologySolution, k)

Compute the nonlinear matter power spectrum from the cosmology solution sol at wavenumber(s) k using halofit implemented in MatterPower.jl.

source

Example

using SymBoltz, Unitful, UnitfulAstro, Plots
M = SymBoltz.ΛCDM()
pars = SymBoltz.parameters_Planck18(M)
prob = CosmologyProblem(M, pars)
ks = 10 .^ range(-5, +2, length=200) / u"Mpc"
sol = solve(prob, ks)

# Linear power spectrum
Ps = spectrum_matter(sol, ks)
plot(log10.(ks*u"Mpc"), log10.(Ps/u"Mpc^3"); xlabel = "log10(k/Mpc⁻¹)", ylabel = "log10(P/Mpc³)", label = "linear (SymBoltz)")

# Nonlinear power spectrum (from halofit)
Ps = spectrum_matter_nonlinear(sol, ks)
plot!(log10.(ks*u"Mpc"), log10.(Ps/u"Mpc^3"); label = "non-linear (halofit)", legend_position = :bottomleft)
Example block output

CMB power spectra

SymBoltz.spectrum_cmbFunction
spectrum_cmb(ΘlAs::AbstractMatrix, ΘlBs::AbstractMatrix, P0s::AbstractVector, ls::AbstractVector, ks::AbstractVector; integrator = TrapezoidalRule(), normalization = :Cl)

Compute the angular power spectrum

\[Cₗᴬᴮ = (2/π) ∫\mathrm{d}k \, k² P₀(k) Θₗᴬ(k,τ₀) Θₗᴮ(k,τ₀)\]

for the given ls. If normalization == :Dl, compute $Dₗ = Cₗ l (l+1) / 2π$ instead.

source
spectrum_cmb(modes::AbstractVector{<:Symbol}, prob::CosmologyProblem, jl::SphericalBesselCache; normalization = :Cl, unit = nothing, kτ0s = 0.1*jl.l[begin]:2π/2:10*jl.l[end], xs = 0.0:0.0008:1.0, l_limber = 50, integrator = TrapezoidalRule(), bgopts = (alg = Rodas4P(), reltol = 1e-9, abstol = 1e-9), ptopts = (alg = KenCarp4(), reltol = 1e-8, abstol = 1e-8), sourceopts = (rtol = 1e-3, atol = 0.9), verbose = false, kwargs...)

Compute angular CMB power spectra $Cₗᴬᴮ$ at angular wavenumbers ls from the cosmological problem prob. The requested modes are specified as a vector of symbols in the form :AB, where A and B are T (temperature), E (E-mode polarization) or ψ (lensing). If unit is nothing the spectra are of dimensionless temperature fluctuations relative to the present photon temperature; while if unit is a temperature unit the spectra are of dimensionful temperature fluctuations. Returns a matrix of $Cₗ$ if normalization is :Cl, or $Dₗ = l(l+1)/2π$ if normalization is :Dl.

The lensing line-of-sight integral uses the Limber approximation for l ≥ l_limber.

Examples

using SymBoltz, Unitful
M = ΛCDM()
pars = parameters_Planck18(M)
prob = CosmologyProblem(M, pars)

ls = 10:10:1000
jl = SphericalBesselCache(ls)
modes = [:TT, :TE, :ψψ, :ψT]
Dls = spectrum_cmb(modes, prob, jl; normalization = :Dl, unit = u"μK")
source
spectrum_cmb(modes::AbstractVector, prob::CosmologyProblem, jl::SphericalBesselCache, ls::AbstractVector; kwargs...)

Same, but compute the spectrum properly only for jl.l and then interpolate the results to all ls.

source

Example

using SymBoltz, Plots
M = SymBoltz.ΛCDM()
pars = SymBoltz.parameters_Planck18(M)
prob = CosmologyProblem(M, pars)

ls = 25:25:3000 # 25, 50, ..., 3000
jl = SphericalBesselCache(ls)
modes = [:TT, :EE, :TE, :ψψ, :ψT, :ψE]
Dls = spectrum_cmb(modes, prob, jl; normalization = :Dl)

Plots.plot(ls, log10.(abs.(Dls)); xlabel = "l", ylabel = "lg(Dₗ)", label = permutedims(String.(modes)))
Example block output

Two-point correlation function

SymBoltz.correlation_functionFunction
correlation_function(sol::CosmologySolution; N = 2048, spline = true)

Compute the two-point correlation function in real space by Fourier transforming the matter power spectrum of sol with N points the FFTLog algorithm implemented in TwoFAST. Returns N radii and correlation function values (e.g. r, ξ).

source

Example

using SymBoltz, Unitful, UnitfulAstro, Plots
M = SymBoltz.ΛCDM()
pars = SymBoltz.parameters_Planck18(M)
prob = CosmologyProblem(M, pars)
ks = 10 .^ range(-5, +3, length=300) / u"Mpc"
sol = solve(prob, ks)
rs, ξs = correlation_function(sol)
rs = rs / (SymBoltz.k0*sol.bg.ps[:h]) * u"Mpc" # TODO: auto units
plot(rs, @. ξs * rs^2; xlims = (0, 200), xlabel = "r", ylabel = "r² ξ")
Example block output

Matter density fluctuations

SymBoltz.variance_matterFunction
variance_matter(sol::CosmologySolution, R)

Compute the variance $⟨δ²⟩$ of the linear matter density field with a top-hat filter with radius R. Wraps the implementation in MatterPower.jl.

source
SymBoltz.stddev_matterFunction
stddev_matter(sol::CosmologySolution, R)

Compute the standard deviation $√(⟨δ²⟩)$ of the linear matter density field with a top-hat filter with radius R.

source
using SymBoltz, Unitful, UnitfulAstro, Plots
M = SymBoltz.ΛCDM()
pars = SymBoltz.parameters_Planck18(M)
prob = CosmologyProblem(M, pars)
ks = 10 .^ range(-5, +3, length=300) / u"Mpc"
sol = solve(prob, ks)

h = sol[M.g.h]
Rs = 10 .^ range(0, 2, length=100) * u"Mpc"
σs = stddev_matter.(sol, Rs)
plot(log10.(Rs/(u"Mpc"/h)), log10.(σs); xlabel = "lg(R / (Mpc/h))", ylabel = "lg(σ)", label = nothing)

R8 = 8 * u"Mpc"/h
σ8 = stddev_matter(sol, R8)
scatter!((log10(R8/(u"Mpc"/h)), log10(σ8)), series_annotation = text("  σ₈ = $(round(σ8; digits=3))", :left), label = nothing)
Example block output

Luminosity distance

SymBoltz.distance_luminosityFunction
distance_luminosity(sol::CosmologySolution, ivs = sol.bg.t, τ0 = sol[sol.prob.M.τ0])

Compute luminosity distances

\[d_L = \frac{r}{a} = \chi \, \mathrm{sinc} (\sqrt{K} (τ₀-τ)),\]

at the independent variable values ivs relative to the (present) time τ0.

source
using SymBoltz, Plots
M = SymBoltz.RMΛ(K = SymBoltz.curvature(SymBoltz.metric()))
pars = Dict(
    M.r.Ω₀ => 5e-5,
    M.m.Ω₀ => 0.3,
    M.K.Ω₀ => 0.1,
    M.r.T₀ => NaN,
    M.g.h => 0.7
)
prob = CosmologyProblem(M, pars)
sol = solve(prob)

zs = 0.0:1.0:10.0
τs = SymBoltz.timeseries(sol, M.g.z, zs) # times at given redshifts
dLs = SymBoltz.distance_luminosity(sol, τs) / SymBoltz.Gpc
plot(zs, dLs; marker=:dot, xlabel="z", ylabel="dL / Gpc", label=nothing)
Example block output

Sound horizon (BAO scale)

SymBoltz.sound_horizonFunction
sound_horizon(sol::CosmologySolution)

Cumulatively integrate the sound horizon

\[ rₛ(τ) = ∫_0^τ dτ cₛ = ∫_0^τ \frac{dτ}{√(3(1+3ρ_b/4ρ_γ))}\]

to the time steps of the solution sol.

source
using SymBoltz, Plots
M = SymBoltz.ΛCDM()
pars = SymBoltz.parameters_Planck18(M)
prob = CosmologyProblem(M, pars)
sol = solve(prob)
τs = sol[M.τ]
rs = sound_horizon(sol)
plot(τs, rs; xlabel = "τ / H₀⁻¹", ylabel = "rₛ / (c/H₀)")
Example block output

Source functions

SymBoltz.source_gridFunction
source_grid(sol::CosmologySolution, Ss::AbstractVector, τs)

Evaluate and return source functions $S(τ,k)$ from the solution sol. The source functions are given by symbolic expressions Ss, and evaluated on a grid with conformal times τs and the same wavenumbers as sol is solved for.

source
source_grid(Ss_coarse::AbstractArray, ks_coarse, ks_fine; ktransform = identity)

Interpolate values Ss_coarse of source functions $S(τ,k)$ from a coarse wavenumber grid ks_coarse to a fine grid ks_fine. The interpolation is linear in ktransform(k) (e.g. identity for interpolation in $k$ or log for interpolation in $\ln k$. Conformal times are unchanged.

source
source_grid(prob::CosmologyProblem, Ss::AbstractArray, τs, ks; bgopts = (), ptopts = (), thread = true, verbose = false)

Compute and evaluate source functions $S(τ,k)$ with symbolic expressions Ss on a grid with conformal times τs and wavenumbers ks from the problem prob.

The options bgopts and ptopts are passed to the background and perturbation solves.

source
SymBoltz.source_grid_adaptiveFunction
source_grid_adaptive(prob::CosmologyProblem, Ss::AbstractVector, τs, ks; bgopts = (), ptopts = (), sort = true, kwargs...)

Adaptively compute and evaluate source functions $S(τ,k)$ with symbolic expressions Ss on a grid with fixed conformal times τs, but adaptively refined grid of wavenumbers from the problem prob. The source functions are first evaluated on the (coarse) initial grid ks. Each subinterval $(k₁, k₂)$ of ks is then adaptively refined until the linear interpolation $Sᵢ = (S(k₁)+S(k₂))/2$ to the midpoint $k=(k₁+k₂)/2$ approximates the actual value $S(k)$ there within some tolerance. The comparison $Sᵢ ≈ S$ is done with isapprox(Sᵢ, S; kwargs...), where S and Sᵢ are vectors with the (conformal) timeseries of the source function for that wavenumber. It receives the keyword arguments kwargs passed to this function, so atol, rtol and/or norm can be specified to tune the tolerance.

Returns the refined wavenumbers sorted in ascending order and a grid with the corresponding source function values. If not sort, the wavenumbers and source function values are instead left in the order in which they were inserted in the refinement process.

The options bgopts and ptopts are passed to the background and perturbation solves.

source
using SymBoltz, Plots, DataInterpolations
M = ΛCDM(h = nothing, ν = nothing)
pars = parameters_Planck18(M)
prob = CosmologyProblem(M, pars)
sol = solve(prob)

τs = sol[M.τ] # conformal times in background solution
ks = [1.0, 2000.0] # initial coarse grid
ks, Ss = source_grid_adaptive(prob, [M.ST0], τs, ks; atol = 5.0)
iτ = argmax(sol[M.b.v]) # index of decoupling time
iτs = iτ-75:iτ+75 # indices around decoupling
p1 = surface(ks, τs[iτs], Ss[1, iτs, :]; camera = (45, 25), xlabel = "k", ylabel = "τ", zlabel = "S", colorbar = false)

lgas = -6.0:0.2:0.0
τs = LinearInterpolation(sol[M.τ], sol[log10(M.g.a)])(lgas) # τ at given lg(a)
ks = 5.0:5.0:100.0
Ss = source_grid(prob, [M.g.Ψ], τs, ks)
p2 = wireframe(ks, lgas, Ss[1, :, :]; camera = (75, 20), xlabel = "k", ylabel = "lg(a)", zlabel = "Φ")

plot(p1, p2)
Example block output

Line-of-sight integration

SymBoltz.los_integrateFunction
los_integrate(Ss::AbstractMatrix{T}, ls::AbstractVector, τs::AbstractVector, ks::AbstractVector, jl::SphericalBesselCache; l_limber = typemax(Int), integrator = TrapezoidalRule(), verbose = false) where {T <: Real}

For the given ls and ks, compute the line-of-sight-integrals

\[Iₗ(k) = ∫dτ S(k,τ) jₗ(k(τ₀-τ))\]

over the source function values Ss against the spherical Bessel functions $jₗ(x)$ cached in jl. The element Ss[i,j] holds the source function value $S(kᵢ, τⱼ)$. The limber approximation

\[Iₗ ≈ √(π/(2l+1)) S(k,τ₀-(l+1/2)/k)\]

is used for l ≥ l_limber.

source