CosmoFit.theory¶
Build a cosmological model from an action rather than from an already-solved expansion history.
Every model in cosmology.models encodes the result of a
derivation somebody did by hand: an E(z) typed in from a
paper. cosmology.custom.define_model() lowers the barrier to
adding one, but not the work – it still wants E(z).
This subpackage takes the input instead of the output. Give it a
gravitational action on an FLRW metric, and it reduces the action
to a point-like Lagrangian, varies the lapse to get the Friedmann
constraint, solves that constraint for E(z), and hands back an
ordinary Cosmology subclass that
every dataset, likelihood, sampler and plot in this library
already knows how to use.
>>> from CosmoFit import Fitter
>>> from CosmoFit.theory import Action
>>>
>>> model = Action(
... "T + alpha * (-T)**b",
... geometry="teleparallel",
... params={
... "alpha": {"default": 1.0, "bounds": (0.0, 20.0)},
... "b": {"default": 0.1, "bounds": (-3.0, 0.99)},
... },
... closure="alpha",
... ).build("PowerLawFT")
>>>
>>> fit = Fitter(
... model=model,
... datasets=["cc", "desi"],
... free_params=["H0", "Omega_m", "b"],
... )
>>> fit.best_fit()
An action can also carry dynamical scalar fields, in which case the expansion history is integrated rather than solved pointwise:
>>> quintessence = Action(
... "R",
... fields={"phi": "X - V0*exp(-lam*phi)"},
... params={
... "V0": {"default": 2.1, "bounds": (0.05, 50.0)},
... "lam": {"default": 0.5, "bounds": (0.0, 1.7)},
... },
... closure="V0",
... ).build("ExponentialQuintessence")
A general f(R) is fourth-order and needs its own reduction,
which happens automatically:
>>> starobinsky = Action(
... "R - 2*Lam + alpha_fr*R**2",
... params={
... "Lam": {"default": 2.1, "bounds": (0.0, 6.0)},
... "alpha_fr": {"default": 1e-3, "bounds": (1e-6, 1.0)},
... },
... ).build("Starobinsky")
The gravitational sector may couple to a field, which is scalar-tensor gravity rather than a field on top of General Relativity – and changes how structure grows as well as how the universe expands:
>>> scalar_tensor = Action(
... "(1 + xi*phi**2)*R",
... fields={"phi": "X - V0"},
... params={
... "xi": {"default": 0.02, "bounds": (-0.5, 0.5)},
... "V0": {"default": 2.1, "bounds": (0.05, 20.0)},
... },
... closure="V0",
... growth="quasi_static", # G_eff/G_N is not 1 here
... ).build("ScalarTensor")
See minisuperspace for the reduction itself,
curvature for the Lagrange-multiplier route a
general f(R) takes and why it integrates backwards,
solve for how a transcendental constraint is solved
on the physical branch, and fields for why a
field’s initial conditions are set early rather than today.
The action¶
User-facing action specification, and the compiler that turns one
into a fittable Cosmology.
minisuperspace does the physics – it reduces an
action on FLRW to a Friedmann constraint. This module wraps that
in something a user can actually write down, and closes the loop
by solving the constraint for E(z) and handing back a model
class that every existing dataset, likelihood, fitter and plot in
CosmoFit already knows how to use.
The distinction from cosmology.custom.define_model() is
where the derivation happens. define_model takes E(z),
which means the user has already done the variational calculus by
hand. Action takes the action, and does that calculus.
Example
Lambda-CDM, written as an action rather than as an answer:
>>> from CosmoFit.theory import Action
>>> LCDM = Action("R - 2*Lam", closure="Lam").build("LCDM_from_action")
>>> c = LCDM(H0=67.4, Omega_m=0.315)
>>> c.E(0.5)
1.2795...
The exponential f(Q) model of Anagnostopoulos, Basilakos &
Saridakis, whose Friedmann equation this rederives:
>>> FQ = Action(
... "Q * exp(lam * Q0 / Q)",
... geometry="symmetric",
... params={"lam": {"default": 0.3}},
... closure="lam",
... growth="quasi_static",
... ).build("FQ_from_action")
- class CosmoFit.theory.action.Fluid(w, parameter)[source]¶
Bases:
objectA perfect fluid with constant equation of state.
- class CosmoFit.theory.action.Action(gravity, *, geometry=None, fluids=('matter',), params=None, closure=None, growth='gr', fields=None, z_init=3000.0)[source]¶
Bases:
objectA gravitational action on an FLRW background, and the machinery to turn it into a fittable model.
- Parameters:
gravity (str) –
The gravitational Lagrangian
f, as an expression in the geometry scalar (R,TorQ), the cosmological parameters, and any parameters declared inparams.R0/T0/Q0are available as the scalar’s value today for a matter-free de Sitter normalization (T0 = -6,Q0 = 6inH0 = 1units), which is how thef(Q)literature writes its models.Written in the sign convention of
minisuperspace: an undeformedf(just"R","T"or"Q") is exactly General Relativity.geometry ({"metric", "teleparallel", "symmetric"}, optional) – Which geometric formulation the action is built on – curvature, torsion, or non-metricity. Inferred from which scalar symbol appears in
gravitywhen only one does.fluids (sequence, optional) – Matter content, as names from
STANDARD_FLUIDSorFluidinstances. Defaults to pressureless matter alone.params (dict, optional) – Model parameters beyond the standard set, in the same
{name: {"default": ..., "bounds": ..., "label": ...}}formcosmology.custom.define_model()takes.closure (str, optional) – Name of the one parameter fixed by requiring
E(0) = 1rather than fit. Every consistent model needs this condition satisfied somehow: in Lambda-CDM it is what makesOmega_de0 = 1 - Omega_m - Omega_k, and in the exponentialf(Q)model it is what makeslama function ofOmega_mrather than a free parameter. If the action satisfies it identically, leave this unset;build()checks and complains either way.growth ({"gr", "quasi_static"}, optional) –
How the linear growth of structure responds to the modification, i.e. what
mu = G_eff/G_Nthe generated model reports."gr"(default) leavesmu = 1: correct whenever the action modifies the background only in the sense that the extra gravitational degrees of freedom do not propagate into sub-horizon clustering – and the safe default, because it is what every dark-energy model assumes."quasi_static"asks for the sub-horizon quasi-static result, which depends on what the action modified:a deformed geometry scalar (
f(T),f(Q)) givesmu = 1/f', what this library’s hand-writtenFQExponentialandFRTLinearalready use;a field coupled to the curvature gives the scalar-tensor result of Boisseau, Esposito-Farese, Polarski & Starobinsky (2000),
mu = (2F + 4 F_phi^2) / (F (2F + 3 F_phi^2))withF = df/dR, evaluated on the field’s own solution so that it moves as the field rolls.
Either way it is an additional physical assumption on top of the action – a statement about perturbations, which a background action does not by itself determine – so it must be asked for explicitly. Asking for it where nothing is modified is an error rather than a no-op.
fields (dict, optional) –
Scalar fields, mapping name -> Lagrangian density written in terms of the field and its kinetic scalar
X("X - V0*exp(-lam*phi)"for exponential quintessence, or any otherL(X, phi)for k-essence). More than one is fine; each gets its own equation of motion.A field’s name is also in scope in
gravity, which is how scalar-tensor gravity is written –"(1 + xi*phi**2)*R"couples the field to curvature rather than adding it on top of General Relativity, and brings the3 H dF/dtterm into the Friedmann equation.A field’s expansion history is integrated rather than solved pointwise – see
fields– and it adds two parameters,<name>_iandd<name>_i, its value anddphi/dNatz_init. Because those are given early rather than today,E(0) = 1becomes a shooting condition, soclosureis required.z_init (float, optional) – Redshift at which a field’s initial conditions are set, and the earliest redshift the resulting model can be evaluated at. Default 3000, which covers recombination. Ignored by an action with no fields.
- property field_lagrangians: dict¶
Each field’s Lagrangian density, as
{name: (expression, X_symbol)}.
- lagrangian()[source]¶
The reduced point-like Lagrangian of this action, together with the minisuperspace it lives on.
- Return type:
tuple[Minisuperspace, Expr]
- constraint()[source]¶
The Friedmann constraint of this action, as an expression in
E2(the squared dimensionless Hubble rate) andz, vanishing on-shell.- Returns:
(expr, E2, z) ((sympy expression, Symbol, Symbol))
- field_equations()[source]¶
Equation of motion for each scalar field in this action (each vanishing on-shell), in the gauge
N = 1.Provided for inspection –
build()integrates this system rather than returning it, so this is the way to see what was actually derived.- Return type:
- closure_equation()[source]¶
The condition
E(0) = 1, as an expression in the model parameters that must vanish.Every model has to satisfy this –
H(z=0)isH0by definition ofH0. What differs is whether the action satisfies it identically (nothing to do), or fixes one parameter in terms of the others.
- build(name, label=None)[source]¶
Compile this action into a
Cosmologysubclass.The returned class is an ordinary CosmoFit model: pass it to
Fitterand every dataset, likelihood, sampler and plot works on it unchanged.An action carrying dynamical scalar fields is integrated rather than solved pointwise – see
fields– and gains two parameters per field,<name>0andd<name>0, its value anddphi/dNata = 1.
- field_system()[source]¶
The compiled equations of motion of this action, for the case where it carries dynamical fields.
Returns
(system, args)– seetheory.fields.build_system(). Cached: assembling it means solving a linear system symbolically.
- curvature_system()[source]¶
The compiled equations of motion of a general
f(R)action. Cached: assembling it means a symbolic solve.
- property coupling: Expr¶
F, the coefficient ofR/2in this action – which isd f / d R. Constant for a minimally coupled field, and a function of the field for scalar-tensor gravity.
- property is_non_minimal: bool¶
Whether the gravitational sector couples to a field – scalar-tensor gravity, where the field sets the strength of gravity rather than sitting on top of it.
The reduction¶
Minisuperspace reduction: from an action to the Friedmann equation.
Every model in cosmology.models was written the other way
round – somebody derived E(z) by hand from a Lagrangian and
typed the result in. This module does the derivation itself, so a
model can be specified the way it is specified in a paper (an
action and a metric) rather than the way it is specified in code
(an already-solved expansion history).
The method is the standard minisuperspace one. Write FLRW with an
explicit lapse N(t),
ds^2 = -N(t)^2 dt^2 + a(t)^2 dSigma_k^2,
substitute it into the action to get a point-like Lagrangian
L(N, Ndot, a, adot, addot, fields, fielddots), and vary. The
lapse is what makes this work: it is a non-dynamical gauge degree
of freedom, so varying it produces a constraint rather than an
evolution equation – and that constraint, evaluated at the gauge
choice N = 1, is exactly the Friedmann equation. Dropping the
lapse from the metric (writing N = 1 from the start) loses it,
which is why it has to be carried through the whole reduction and
only set to 1 at the very end.
Because L contains addot for curvature-based gravity, the
reduction integrates by parts first, discarding the resulting
total time derivative – legitimate exactly when L is linear
in addot, which holds for General Relativity, a non-minimally
coupled F(phi) R, and every f(T) / f(Q) (whose scalars
contain no addot at all). It fails for a general f(R),
which is genuinely fourth-order; reduce_order() raises
rather than silently discarding a term that is not a total
derivative, and curvature handles that case by
making R an independent variable first – after which the
reduction here applies again unchanged.
Units¶
Everything here is dimensionless: kappa = 8 pi G = 1,
H0 = 1, time in units of 1/H0. In these units the GR
Friedmann equation is 3 H^2 = rho, so a fluid with today’s
density parameter Omega_i has rho_i0 = 3 Omega_i, and
spatial curvature enters as k = -Omega_k.
Sign conventions¶
The three geometry scalars carry different signs in the
literature, and picking one at random silently flips the sense of
every modification. They are fixed here by one requirement: the
undeformed action f = R, f = T or f = Q must
reproduce General Relativity exactly. That gives
- R = 6 [ addot/(a N^2) + adot^2/(a^2 N^2)
adot Ndot/(a N^3) + k/a^2 ], L_g = +N a^3 f(R)/2
T = -6 adot^2/(a^2 N^2) (= -6 H^2), L_g = +N a^3 f(T)/2
Q = +6 adot^2/(a^2 N^2) (= +6 H^2), L_g = -N a^3 f(Q)/2
and test_theory.py asserts the GR limit for all three rather
than trusting the table.
- CosmoFit.theory.minisuperspace.GEOMETRIES = ('metric', 'teleparallel', 'symmetric')¶
The three geometry sectors this module can reduce.
- CosmoFit.theory.minisuperspace.GEOMETRY_SCALAR = {'metric': 'R', 'symmetric': 'Q', 'teleparallel': 'T'}¶
Symbol each sector’s gravitational Lagrangian is a function of.
- class CosmoFit.theory.minisuperspace.Minisuperspace(fields=(), curvature=False)[source]¶
Bases:
objectThe symbols and functions of one FLRW minisuperspace.
Holds the time coordinate, the lapse
N(t), the scale factora(t), the curvature constantkand any scalar fields, so the pieces below all talk about the same objects.- Parameters:
fields (sequence of str, optional) – Names of scalar fields living on this background. Each becomes a
sympy.Functionoft.curvature (bool, optional) – Carry the Ricci scalar as an independent dynamical variable
R(t)rather than as shorthand for a combination ofaand its derivatives. That is what makes a generalf(R)reducible – seecurvature.
- property coordinates¶
a, every field, and the curvature variable where there is one.- Type:
The dynamical coordinates
- geometry_scalar(geometry)[source]¶
The curvature / torsion / non-metricity scalar of this minisuperspace, in the sign convention fixed in the module docstring.
- Returns:
(expr, sign) ((sympy expression, int)) –
expris the scalar;signmultiplies the gravitational LagrangianN a^3 f(scalar) / 2so that an undeformedfgives General Relativity.- Parameters:
geometry (str)
- CosmoFit.theory.minisuperspace.fluid_lagrangian(ms, densities)[source]¶
Minisuperspace Lagrangian of a set of perfect fluids.
A fluid with constant equation of state
whasrho(a) = rho_0 a^{-3(1+w)}, and contributes-sqrt(-g) rho = -N a^3 rho(a) = -N rho_0 a^{-3w}. Pressureless matter (w = 0) therefore contributes a term with no scale-factor dependence at all, and radiation (w = 1/3) one going as1/a– the familiar forms.- Parameters:
densities (dict) – Maps
w(as a sympy-compatible number) to today’s densityrho_0(in units where3 H0^2 = 1, i.e.rho_0 = 3 Omega).ms (Minisuperspace)
- Return type:
Expr
- CosmoFit.theory.minisuperspace.gravity_lagrangian(ms, geometry, f, scalar_symbol)[source]¶
Minisuperspace Lagrangian of the gravitational sector,
sign * N a^3 f(scalar) / 2with the scalar substituted for its FLRW expression (kappa = 1).fis given as an expression inscalar_symbol(plus any model parameters and fields); the substitution happens here so that everything downstream differentiates through ordinary sympy chain rules, with no abstractFunctionleft to trip over.- Parameters:
ms (Minisuperspace)
geometry (str)
f (Expr)
scalar_symbol (Symbol)
- Return type:
Expr
- CosmoFit.theory.minisuperspace.field_lagrangian(ms, lagrangians)[source]¶
Minisuperspace Lagrangian of the scalar-field sector.
Each field’s Lagrangian density is given as an expression in the field itself and its kinetic scalar
X; on FLRW,X = -g^{mu nu} d_mu phi d_nu phi / 2 = phidot^2 / (2 N^2),
so a canonical field is
X - V(phi)and a k-essence one is any other function of(X, phi). The contribution to the point-like Lagrangian issqrt(-g) L = N a^3 L(X, phi).- Parameters:
lagrangians (dict) – Maps field name ->
(lagrangian_expr, X_symbol).ms (Minisuperspace)
- Return type:
Expr
- CosmoFit.theory.minisuperspace.reduce_order(L, ms)[source]¶
Remove second time derivatives from
Lby integrating by parts and discarding the total derivative.For a Lagrangian linear in
qddot, writingL = A qddot + Band droppingd(A qdot)/dtleavesL - A qddot - Adot qdot, which has the same equations of motion. This is what turns the Einstein-Hilbert term (which containsaddot) into the familiar-3 a adot^2 / N.- Raises:
ValueError – If
Lis nonlinear in someqddot– the case of a generalf(R), which is genuinely fourth-order. Then the discarded piece is not a total derivative and dropping it would quietly change the theory, so this refuses instead.- Parameters:
L (Expr)
ms (Minisuperspace)
- Return type:
Expr
- CosmoFit.theory.minisuperspace.euler_lagrange(L, q, t)[source]¶
Euler-Lagrange expression
dL/dq - d/dt (dL/dqdot).- Parameters:
L (Expr)
- Return type:
Expr
- CosmoFit.theory.minisuperspace.friedmann_constraint(L, ms)[source]¶
The Friedmann equation: vary
Lwith respect to the lapse, then fix the gaugeN = 1.Returned as an expression that vanishes on-shell (the equation is
constraint == 0). The overall normalization is whatever the variation produces – only the zero set matters – so a comparison against a textbook form should allow an arbitrary non-zero factor.- Parameters:
L (Expr)
ms (Minisuperspace)
- Return type:
Expr
- CosmoFit.theory.minisuperspace.field_equations(L, ms)[source]¶
Equation of motion for each scalar field, in the gauge
N = 1. Each vanishes on-shell.- Parameters:
L (Expr)
ms (Minisuperspace)
- Return type:
Solving the constraint¶
Solving a Friedmann constraint for E(z).
action produces an expression C(E2, z; params)
that vanishes on-shell. Turning that into the E(z) every
distance, likelihood and plot in CosmoFit calls means solving it,
and the constraint of an interesting model is rarely a polynomial
– the exponential f(Q) model’s is transcendental, and its
hand-written counterpart in this library needs a Lambert W to
invert. So there are two paths here:
a closed form, when sympy can solve the constraint for
E2and returns exactly one branch. Vectorized and exact.a continuation solve otherwise. Newton’s method on the whole redshift array at once, walked out from
z = 0– where the closure condition guaranteesE2 = 1– along a ladder of intermediate redshiftss*z, each step seeded by the last.
The continuation is what makes branch selection well-posed. A
transcendental constraint generally has several roots, and a
root-finder handed the whole redshift range at once can land on a
different branch at different z and return a discontinuous,
physically meaningless E(z) without failing. Starting from the
known root at z = 0 and never letting the solution jump
follows one branch by construction – the same reason
FQExponential has to pick a specific Lambert W branch
rather than any root of its equation.
The derivative dE/dz is never finite-differenced: implicit
differentiation of the constraint gives
dE2/dz = -(dC/dz) / (dC/dE2)
exactly, from expressions sympy already has.
- CosmoFit.theory.solve.compile_constraint(C, E2, z, args)[source]¶
Lambdify a constraint and its two partial derivatives.
Only the numerator of the constraint is used. A constraint assembled from a Lagrangian routinely carries a denominator in
a(equivalently1 + z) which never vanishes on the physical domain, and clearing it keeps Newton’s method away from spurious poles.- Parameters:
args (sequence of Symbol) – Parameter symbols, in the order the returned callables expect them after
(E2, z).C (Expr)
E2 (Symbol)
z (Symbol)
- Returns:
(value_and_slope, df_dz) (tuple of callables) –
value_and_slope(E2, z, *params)returns the pair[C, dC/dE2];df_dz(E2, z, *params)returnsdC/dz.
- CosmoFit.theory.solve.closed_form(C, E2, z, args)[source]¶
Try to solve the constraint for
E2symbolically.Returns a lambdified
E2(z, *params)if sympy finds exactly one solution, elseNone– more than one branch is treated as “no closed form” rather than resolved by guesswork, and left to the continuation solve, which picks the branch physically.- Parameters:
C (Expr)
E2 (Symbol)
z (Symbol)
- CosmoFit.theory.solve.solve_E2(z, functions, values, *, seed=None)[source]¶
Solve
C(E2, z) = 0forE2on a whole redshift array.Walks out from
z = 0, whereE2 = 1by the closure condition, along_CONTINUATION_STEPSintermediate redshifts, running Newton’s method at each. Every point of the array is advanced together, so this costs a fixed number of vectorized passes rather than a root-find per redshift.- Parameters:
z (ndarray) – Redshifts. May be in any order, and may include negative values (the future), which the continuation handles the same way.
functions (tuple) –
(value_and_slope, df_dz)fromcompile_constraint().values (tuple) – Parameter values, matching the order given to
compile_constraint().seed (ndarray, optional) – Starting guess. When given, the continuation ladder is skipped and Newton runs directly, on the understanding that the seed is already near the right branch – the residual is checked either way, and a failed direct solve falls back to the full ladder. Defaults to
None, i.e. walking out fromE2 = 1atz = 0.
- Returns:
ndarray –
E2at each redshift.- Raises:
RuntimeError – If Newton fails to converge, rather than returning a number that merely looks like a solution.
Dynamical fields¶
Integrating an action that carries dynamical scalar fields.
solve handles actions whose Friedmann constraint
determines E(z) on its own – f(T), f(Q), General
Relativity with a cosmological constant. Add a scalar field and
that stops being true: the constraint now involves the field and
its velocity, which have their own equation of motion, and the
expansion history has to be integrated rather than solved
pointwise.
The system¶
In e-folds N = ln a, with u = dphi/dN, the state is
(H, phi, u) and the equations come out of what
minisuperspace already derived, with no further
physics typed in:
the Friedmann constraint
C(a, H, phi, u) = 0one Euler-Lagrange equation per field
The trick is that the constraint is a first integral of the
equations of motion – so instead of separately deriving the
acceleration equation (varying a), this differentiates the
constraint along the solution,
- dC/dN = a dC/da + (dC/dH) H’ + sum_i [ (dC/dphi_i) u_i
(dC/du_i) u_i’ ] = 0,
and solves that together with the field equations for the
unknowns H' and u_i'. The two routes are equivalent by the
Bianchi identity, and this one reuses expressions already in hand.
It also leaves the constraint as an independent check on the
integration: it is imposed only in the initial conditions, so how
far it drifts along the solution measures the error.
Initial conditions, and why they are set early¶
Each field contributes two parameters – phi_i and dphi_i,
its value and dphi/dN – imposed at an early time
z = z_init, and the system is integrated forwards from
there.
Setting them at a = 1 instead would be far more convenient:
H = 1 holds there by the definition of H0, so the closure
condition E(0) = 1 would be algebraic and no shooting would be
needed at all. It is also wrong. Integrating backwards from a
field at rest today, the Hubble friction -3u that damps the
field forwards in time becomes anti-friction, the generic past
solution is kinetic-dominated, and rho_phi grows as a^-6:
for exponential quintessence with the potential normalized to
today’s dark-energy density, that gives E(2.5) = 9.3 where
Lambda-CDM gives 3.7. Nothing about the calculation fails – it is
the correct past of those initial conditions, and those initial
conditions are not a universe.
So the field’s state is specified where a quintessence model
actually specifies it, early and typically frozen
(dphi_i = 0), and E(0) = 1 becomes a shooting condition
on whichever parameter Action(closure=...) names. Forwards is
also the numerically stable direction, since the friction term
that amplified error backwards now damps it.
The cost is that closure needs a handful of integrations rather
than one evaluation, and that E(z) is only defined out to
z_init – beyond which there is no history, and asking for one
is an error rather than an extrapolation.
- class CosmoFit.theory.fields.FieldSystem(constraint, equations, state, derivatives, args, densities=None)[source]¶
Bases:
objectThe equations of motion of an action with dynamical fields, compiled to a right-hand side
solve_ivpcan integrate.- Parameters:
constraint (sympy expression) – The Friedmann constraint, already written in terms of the state symbols.
equations (list of sympy expressions) – One Euler-Lagrange equation per field, in the same terms.
state (tuple) –
(a, H, phis, us)– the symbols the above are written in.derivatives (tuple) –
(dH, dus)– the symbols standing fordH/dNand eachdu_i/dN.args (tuple of Symbol) – Parameter symbols, in the order the compiled callables take them.
- symbolic_constraint¶
the closure condition E(0) = 1 is this same constraint at a = 1, H = 1, which is how a field action reuses Action(closure=…) unchanged.
- Type:
Kept symbolically as well
- CosmoFit.theory.fields.build_system(action)[source]¶
Assemble the
FieldSystemof anAction.Everything here is substitution: the reduction and the variation already happened in
minisuperspace. What changes is the independent variable, from coordinate time to e-folds, viaadot = a H, addot = a (H^2 + H H’), phidot = H u, phiddot = H u H’ + H^2 u’
with
'meaningd/dN.- Return type:
- class CosmoFit.theory.fields.History(N_lo, N_hi, splines, drift)[source]¶
Bases:
objectA solved expansion history:
HanddH/dNas functions ofN = ln a, over the range that has been integrated so far.Held as a cubic Hermite spline with derivatives taken from the equations of motion rather than estimated from the samples – the same construction the rest of the library uses for its distance integrals.
- splines¶
H first, then each field, then each field velocity. The fields are kept because the dark-energy density and pressure are read off them rather than off E(z).
- Type:
One spline per state variable
- drift¶
Largest relative drift of the Friedmann constraint over the solution. The constraint is imposed only in the initial conditions, so this is an independent measure of the integration error.
- CosmoFit.theory.fields.initial_state(system, values, fields, velocities, a_i)[source]¶
The state vector
[H, *phis, *us]ata = a_i, withHtaken from the Friedmann constraint.
- CosmoFit.theory.fields.expansion_today(system, values, fields, velocities, a_i)[source]¶
Hata = 1from integrating forwards out ofa_i.This is the residual the closure condition drives to 1, so it runs without
t_eval– only the endpoint is wanted, and asking for samples along the way would pay for output nobody reads.- Return type:
- CosmoFit.theory.fields.integrate(system, values, fields, velocities, a_i, N_hi)[source]¶
Integrate the field system forwards from
a_iand build the interpolating history.- Parameters:
system (FieldSystem)
values (tuple) – Parameter values, in the order
systemexpects.fields (sequence of float) – The field state at
a_i.velocities (sequence of float) – The field state at
a_i.a_i (float) – Initial scale factor,
1/(1 + z_init).N_hi (float) – Upper end of
N = ln ato cover. Positive when the future is wanted (w(z)and the deceleration parameter are plotted there).
- Return type:
Fourth-order actions¶
Fourth-order gravity: a general f(R).
minisuperspace reduces an action by integrating the
addot in the Einstein-Hilbert term away by parts, which is
legitimate only while the Lagrangian is linear in it. A general
f(R) is not, and the reduction refuses – for good reason: the
term it would discard is not a total derivative, and dropping it
returns a different theory with nothing to show for it.
The Lagrange-multiplier route¶
The standard way round is to stop treating R as shorthand for a
combination of a and its derivatives, and make it an
independent variable held to that combination by a multiplier:
S = (1/2) integral dt { N a^3 f(R) - lambda (R - R_geom) }.
Varying lambda returns R = R_geom; varying R gives
lambda = N a^3 f'(R). Substituting that back,
L = (1/2) N a^3 [ f(R) - f’(R) R + f’(R) R_geom ],
which is linear in addot – because R_geom is, and it now
appears only multiplied by f'(R). So the ordinary reduction
applies again, at the cost of one extra dynamical variable. That
extra variable is the theory’s fourth order, made visible.
The system¶
What comes out is smaller than “fourth order” suggests. In e-folds,
with the state (H, R):
varying
Rgives backR = 6(2H^2 + H dH/dN), i.e. an explicitdH/dN;the Friedmann constraint is linear in
dR/dN, so it gives an explicitdR/dN.
Two first-order equations. The price is where dR/dN divides by
f''(R): as the theory approaches General Relativity that
vanishes, the equation stiffens, and the integration gets slower
without ever becoming wrong. That is measured in
tests/test_theory_curvature.py rather than asserted.
Direction of integration¶
Backwards, from today. That is the opposite of what
fields does, and the difference is not an
inconsistency – it is what the two systems actually do.
A scalar field integrated backwards runs away: the Hubble friction
that damps it forwards becomes anti-friction, and the generic past
solution is kinetic-dominated. The f(R) scalaron does not. A
relative perturbation of 1e-8 in today’s R changes E(z)
by less than that out to z = 1100, and loosening the
integrator’s tolerance a hundredfold moves it by 1e-8. Both are
measured. So there is no shooting here and no early initial
condition: H = 1 at a = 1 holds by construction, and the
model’s extra freedom is carried by R today.
- CosmoFit.theory.curvature.is_higher_order(f, scalar)[source]¶
Whether
fis nonlinear in the geometry scalar, and so needs this module rather than the ordinary reduction.- Parameters:
f (Expr)
scalar (Symbol)
- Return type:
- CosmoFit.theory.curvature.multiplier_lagrangian(ms, f, scalar)[source]¶
The gravitational Lagrangian of
f(R)withRpromoted to an independent variable, as set out in the module docstring.- Parameters:
ms (Minisuperspace) – Must carry a curvature variable (
ms.R).f (sympy expression) –
fin terms ofscalar.scalar (Symbol) – The symbol
fis written in.
- Return type:
Expr
- class CosmoFit.theory.curvature.CurvatureSystem(constraint, curvature_equation, acceleration, state, derivatives, args)[source]¶
Bases:
objectAn
f(R)background, compiled to a right-hand side in(H, R)overN = ln a.Built from the two expressions the reduction produces: the equation that comes from varying
R(explicit indH/dN) and the Friedmann constraint (linear indR/dN).
- CosmoFit.theory.curvature.build_system(action)[source]¶
Assemble the
CurvatureSystemof anf(R)Action.
- CosmoFit.theory.curvature.integrate(system, values, R_today, N_lo, N_hi)[source]¶
Integrate the
f(R)background outwards froma = 1, whereH = 1by the definition ofH0.- Parameters:
system (CurvatureSystem)
values (tuple) – Parameter values, in the order
systemexpects.R_today (float) – The Ricci scalar today, in units of
H0^2. This is the model’s extra initial condition – the freedom a fourth-order theory has and General Relativity does not.N_lo (float) – Range of
N = ln ato cover.N_hi (float) – Range of
N = ln ato cover.
- Return type: