Skip to content

eft4py Output

Solve a Horndeski dark-energy background with eft4py, plot it with cplots, and compare it with ΛCDM from CAMB, all through the same as_observables / background() calls.

Not executed during the docs build

eft4py is not a docs dependency, so the code below is shown verbatim. The full, interactive version is the marimo notebook notebooks/eft4py_background.py, which declares its dependencies inline:

uvx marimo edit --sandbox --python 3.11 notebooks/eft4py_background.py


Solve

Quintessence, $G_2 = X - V\phi^2$ and $G_4 = M_{\rm pl}^2/2$, with the field at rest at $a = 10^{-6}$ and $V$ tuned so that $H(a=1) = H_0$:

import numpy as np
import sympy as sp
import cplots
from eft4py import Cosmology, HorndeskiModel, ScipyBackground, frozen_field, get_symbols

s = get_symbols()
V = sp.Symbol("V", positive=True)
model = HorndeskiModel(G2=s.X - V * s.phi**2, G4=s.Mpl**2 / 2, parameters=[V])

h, phi_ini = 0.7, 3.0
Omega_r = Cosmology.from_physical(h=h, omega_b=0.0245, omega_cdm=0.1225).Omega_r
cosmo = Cosmology(h=h, Omega_m=0.3, Omega_r=Omega_r)

solver = ScipyBackground(model, [V], ic=frozen_field(phi_ini), a_ini=1e-6, rtol=1e-9)
theta = solver.shoot([cosmo.Omega_de * 3 * cosmo.H0**2 / phi_ini**2], cosmo, index=0)
grid = solver.solve(theta, cosmo, np.linspace(np.log(1 / 11), 0.0, 400))  # z = 10 -> 0

Wrap and plot

as_observables recognises the eft4py grid; BackgroundPanels puts each kind of quantity on its own panel, with the units you ask for:

out = cplots.as_observables(grid)            # -> Eft4pyOutput
out.available_background()                   # canonical names + raw eft4py fields

cplots.BackgroundPanels(
    out,
    ["H", "dL", "dA", "dC", "w_de", "Omega_de", "alpha_M"],
    units={"H": "km/s/Mpc"},
    ncols=3,
    latex_labels=True,
).show("plotly")

hi_class format

eft4py exports its grid in hi_class's format, which is what the adapter reads:

table = grid.to_hiclass()
table["H [1/Mpc]"], table["kineticity_smg"], table["(.)rho_smg"]

So an eft4py run and a hi_class run come out of cplots with the same names and units, and overlay directly:

cplots.BackgroundEvolution({"eft4py": grid, "hi_class": cosmo_hiclass}, ["alpha_B"]).show()

Any redshift grid

z= resamples. A BackgroundSolution uses eft4py's own interpolators:

from eft4py.solvers import BackgroundSolution

z = np.linspace(0.01, 3.0, 60)
sol = cplots.as_observables(BackgroundSolution.from_grid(grid))
cplots.BackgroundEvolution(sol, ["dA", "dC"], z=z, latex_labels=True).show()

Compare with CAMB

CAMB's H is in km/s/Mpc and eft4py's in 1/Mpc; the overlay converts to the units requested (or to the first source's):

import camb

pars = camb.set_params(H0=70, ombh2=0.0245, omch2=0.3 * h**2 - 0.0245, mnu=0.0, omk=0.0)

cplots.BackgroundPanels(
    {"eft4py": grid, r"CAMB ($\Lambda$CDM)": camb.get_background(pars)},
    ["H", "dA"],
    z=z,
    units={"H": "km/s/Mpc"},
    latex_labels=True,
).show()

A frozen field (large $\phi_{\rm ini}$) sits on ΛCDM; a light one rolls and departs from it at late times.