cosmofit.core and cosmofit.samplers

The core of the 2.0 rewrite: theories, likelihoods and samplers assembled from an input. See the module docstring below for what runs on it today.

The new core: theories, likelihoods and samplers assembled from an input.

Status: phase 4 of the 2.0 rewrite. The core runs every model and dataset the library has – natively (cosmofit.theories, cosmofit.likelihoods.native) or through the wrappers in core.legacy – with the samplers of cosmofit.samplers (evaluate, minimize, profile, fisher, mcmc, emcee, nested), getdist output, and core.post to reweight a finished run. Fitter remains the interface the GUI and notebooks use until phase 5.

from cosmofit.core import run

info, sampler = run('''
theory:
  legacy_cosmology: {model: LCDM, compute_rd: true}
likelihood:
  desi:
  omega_b:
params:
  H0:      {prior: {min: 50, max: 90}, latex: H_0}
  Omega_m: {prior: {min: 0.1, max: 0.6}}
  Omega_b: {prior: {dist: norm, loc: 0.049, scale: 0.005, min: 0.03, max: 0.07}}
sampler:
  minimize: {starts: 3}
''')

sampler.products()["point"]

What each part is:

  • core.priors – normalized priors (uniform, Gaussian and truncated Gaussian, log-uniform).

  • core.parameters – sampled, fixed, dependent and derived parameters.

  • core.component – the Theory/Likelihood base classes, requirements and the parameter-keyed cache.

  • core.model – assembly and the log-posterior.

  • core.registry – names to classes: built-ins, import paths, entry points.

  • core.info – the input, as a dict or YAML.

  • core.output – what a run writes, and resuming it.

  • core.mpi – processes sharing a run.

  • core.post – importance reweighting of a finished run.

Priors

Prior distributions for sampled parameters.

Every prior here is a normalized one-dimensional density. The old fitting path only knew a uniform box and returned 0 inside it, which is enough for an MCMC (a constant cancels) and not enough for anything that compares numbers across fits: an evidence, a MAP point under a Gaussian prior, an importance weight. logpdf here is the real log-density.

Each prior also carries what a sampler needs from it besides the density:

ppf

The inverse CDF, mapping the unit interval onto the parameter – the prior transform a nested sampler integrates through.

sample

Draws, for starting points and prior-predictive checks.

support

The interval outside which the density is zero (possibly infinite), for optimizer bounds.

center, scale

A typical value and a typical width, so that a sampler can start somewhere sensible and an optimizer can work in units where every parameter moves by order one.

Specified in an input as a dict – {"min": 0.1, "max": 0.5}, {"dist": "norm", "loc": 0.0224, "scale": 0.0005}, {"dist": "loguniform", "min": 1e-6, "max": 1e-2} – or as a (min, max) pair; see make_prior().

class cosmofit.core.priors.Prior[source]

Bases: object

A normalized one-dimensional prior.

as_dict()[source]

How an input writes this prior (make_prior() reads it back).

Return type:

dict

sample(rng)[source]

One draw, by inverse-CDF sampling.

Parameters:

rng (Generator)

Return type:

float

class cosmofit.core.priors.Uniform(min, max)[source]

Bases: Prior

Uniform on [min, max].

Parameters:
as_dict()[source]

How an input writes this prior (make_prior() reads it back).

Return type:

dict

class cosmofit.core.priors.Gaussian(loc, scale, min=-inf, max=inf)[source]

Bases: Prior

Normal with mean loc and standard deviation scale, optionally truncated to [min, max] and renormalized there.

Parameters:
as_dict()[source]

How an input writes this prior (make_prior() reads it back).

Return type:

dict

class cosmofit.core.priors.LogUniform(min, max)[source]

Bases: Prior

Uniform in ln x on [min, max], 0 < min < max – the prior that says “no preferred order of magnitude”.

Parameters:
as_dict()[source]

How an input writes this prior (make_prior() reads it back).

Return type:

dict

cosmofit.core.priors.make_prior(spec)[source]

Build a Prior from how an input writes one.

Accepts a Prior (returned as is), a (min, max) pair (uniform), or a dict:

  • {"min": a, "max": b} – uniform

  • {"dist": "norm", "loc": m, "scale": s} – Gaussian, with optional min/max truncation

  • {"dist": "loguniform", "min": a, "max": b}

Raises:

ValueError – For anything else, naming what was not understood.

Return type:

Prior

Parameters

Parameters: what is sampled, what is fixed, what is computed.

The old fitting path had one global dataclass holding every parameter of every model, a list of names to free, and a uniform box per name. Here each parameter is declared by itself, in one of four roles:

sampled

Has a prior; the sampler moves it. {"prior": {...}}, with an optional ref (where to start), proposal (a step scale) and latex label.

fixed

A number. H0: 67.4, or {"value": 67.4}.

dependent

An input computed from other parameters before anything is evaluated – a reparametrization. Omega_b: "lambda omega_b, H0: omega_b / (H0 / 100) ** 2" lets a fit sample omega_b (with drop: True, so no component is handed it) and give the cosmology the Omega_b it expects.

derived

An output, recorded with each point and never fed back: {"derived": True} for a value a component computes, or a lambda of other parameters and derived values.

A lambda may be a Python callable or a string "lambda a, b: ...", evaluated with np in scope. Its argument names are the parameters it reads, so the dependency is declared by the signature itself.

class cosmofit.core.parameters.ParamSpec(name, prior=None, value=None, ref=None, proposal=None, latex=None, derived=False, drop=False, arguments=<factory>)[source]

Bases: object

One parameter’s declaration. Build it with parse_param().

Parameters:
property role: str

"sampled", "fixed", "dependent" or "derived".

declaration()[source]

This parameter as an input’s params block would declare it – parse_param() reads it back. A function read from a lambda string is written as that string; one passed as a Python callable only by name, which does not read back.

Return type:

dict | float

class cosmofit.core.parameters.ParameterSet(specs)[source]

Bases: object

Every parameter of a model, by role, and the operations a sampler needs on them.

Parameters:

specs (dict[str, ParamSpec | Any]) – Parsed (or parseable) declarations, keyed by name.

property inputs: list[str]

sampled (unless dropped), fixed and dependent.

Type:

Names handed to components

as_dict(point)[source]

point – a dict, or an array in sampled order – as a {name: value} dict of the sampled parameters.

Return type:

dict

all_values(point)[source]

Sampled, fixed and dependent values together, dependents computed.

Return type:

dict

to_input(point)[source]

The values components receive: all_values() without the dropped parameters.

Return type:

dict

logprior(point)[source]

Sum of the sampled parameters’ normalized log-priors.

Return type:

float

bounds()[source]

Prior support of each sampled parameter, in order.

Return type:

list[tuple[float, float]]

centers()[source]

Each sampled parameter’s ref value, or prior center.

Return type:

ndarray

scales()[source]

A typical step per sampled parameter: proposal if given, else the ref width, else the prior’s.

Return type:

ndarray

sample_ref(rng, tries=1000)[source]

A starting point: drawn from each ref (or the prior), kept inside the prior.

Parameters:
  • rng (Generator)

  • tries (int)

Return type:

ndarray

compute_derived(values, provided)[source]

Every derived parameter: from provided (component outputs) when declared derived: True, else from its lambda over values and what has been derived so far.

Parameters:
Return type:

dict

cosmofit.core.parameters.parse_param(name, spec)[source]

Read one entry of an input’s params block.

Raises:

ValueError – For an entry that does not make a parameter, saying why.

Parameters:
Return type:

ParamSpec

Components

Theories, likelihoods, and how they find each other.

A likelihood says what it needs – get_requirements() returns {"H": {"z": [...]}, "rd": None} – and reads it back through self.provider when asked for a log-likelihood. It never touches a cosmology object or a parameter container.

A theory says what it can provide (get_can_provide()), is told what is wanted of it (must_provide(**requirements)), and computes it in calculate(state, want_derived, **params) into a fresh state dict. Results are read back through get_result(name, **kwargs) or a get_<name> method.

Model does the wiring: it matches each requirement to the one theory that provides it, orders theories so that a theory’s own requirements are computed before it is, and hands every component the parameters it accepts.

Caching is by parameter value. A theory keeps its last few states keyed on the exact input values it was computed at, so asking again at the same point costs nothing, and a likelihood can never read a result computed at different parameters than the ones it was given. The old fitting path depended instead on every caller remembering to call refresh() after changing a parameter – and the one that did not (stats.derived) evaluated every sample on a stale background.

class cosmofit.core.component.Component(info=None, name=None)[source]

Bases: object

Base of theories and likelihoods.

Parameters:
  • info (dict, optional) – This component’s options from the input.

  • name (str, optional) – The name it was listed under; defaults to the class name.

  • attributes (Class)

  • ----------------

  • params (dict) – Parameters this component owns, with default declarations – a likelihood’s nuisance parameters and their priors, say. The input’s params block overrides them.

params: dict = {}

Parameters this component owns, {name: declaration}.

initialize()[source]

Set up from self.info. Override; called by __init__.

Return type:

None

initialize_with_provider(provider)[source]

Called once every component exists and requirements are resolved, with the provider this component reads through.

Parameters:

provider (Provider)

Return type:

None

initialize_complete()[source]

Called once every component has its provider. For setup that must wait for other components to be ready.

Return type:

None

check_model(model)[source]

Called last, with the assembled Model, for checks that need to see the whole of it – which datasets are combined, which parameters are sampled. Warn or raise here.

Return type:

None

accepts(name)[source]

Whether this component takes the input parameter name. Defaults to the names in params.

Parameters:

name (str)

Return type:

bool

get_default_params()[source]

Default declarations for parameters this component owns, overridden by the input’s params. params unless a component’s defaults depend on its options.

Return type:

dict

get_requirements()[source]

What this component needs from theories: {quantity: options or None}.

Return type:

dict

get_required_params()[source]

Input parameters this component cannot run without. Assembly fails, naming them, if the input does not provide them.

Return type:

list[str]

get_derived_params()[source]

Names of the derived parameters this component can output.

Return type:

list[str]

class cosmofit.core.component.Theory(info=None, name=None)[source]

Bases: Component

A component that computes quantities for others.

Subclasses implement get_can_provide(), calculate(), and either get_result() or get_<name> methods.

Parameters:
  • info (dict | None)

  • name (str | None)

cache_size: int = 3

How many past states to keep. A theory wrapping a single mutable object can only hold one, and says so by setting 1.

current_key: tuple | None

Cache key of current_state; see compute().

n_calculations

Calls of calculate(), as opposed to cache hits.

get_can_provide()[source]

Quantities this theory can compute.

Return type:

list[str]

must_provide(**requirements)[source]

Record what is wanted of this theory. Called once per requiring component; the default merges the requests by name.

Return type:

None

calculate(state, want_derived=True, **params)[source]

Compute everything requested at params into state. Return False if the parameters admit no solution (the point is then rejected, not an error).

Parameters:
Return type:

bool | None

compute(params, want_derived=True, upstream=())[source]

Make current_state the state at params, from the cache if it holds one. Returns False if calculate() rejected the point.

upstream identifies the current states of the theories this one reads (their current_key). It is part of the cache key: a theory with no parameters of its own – one that reads everything from another – must still recompute when what it reads has changed.

Parameters:
Return type:

bool

get_result(name, *args, **kwargs)[source]

A computed quantity from the current state. The default looks for a get_<name> method, then for state[name].

Parameters:

name (str)

Return type:

Any

class cosmofit.core.component.Likelihood(info=None, name=None)[source]

Bases: Component

A component that returns a log-likelihood.

Subclasses implement logp(), reading theory results through self.provider.

Parameters:
  • info (dict | None)

  • name (str | None)

logp(**params)[source]

ln L at the current point. params are this likelihood’s own input parameters (its nuisance parameters, say).

Return type:

float

class cosmofit.core.component.Provider(providers)[source]

Bases: object

What a component reads theory results through.

provider.get_result("H", z=...) asks the theory that provides "H"; provider.get_H(z=...) is the same thing.

Parameters:

providers (dict[str, Theory])

theory_for(name)[source]

The theory that provides name.

Parameters:

name (str)

Return type:

Theory

property provides: dict[str, str]

{quantity: theory name}.

exception cosmofit.core.component.ComponentError[source]

Bases: ValueError

A model that cannot be assembled: a requirement nobody provides, a parameter nobody uses, a cycle between theories.

The model

A model: theories, likelihoods and parameters, assembled from an input, evaluated as one log-posterior.

model = get_model({
    "theory": {"legacy_cosmology": {"model": "LCDM"}},
    "likelihood": {"cc": None, "desi": {"version": "desi2025"}},
    "params": {
        "H0": {"prior": {"min": 50, "max": 90}},
        "Omega_m": {"prior": {"min": 0.1, "max": 0.6}},
        "rd": 147.1,
    },
})

result = model.logposterior({"H0": 68.0, "Omega_m": 0.31})
result.logpost, result.loglikes, result.chi2

Assembly checks everything that can be checked before a single point is evaluated, and fails with a message naming the problem: a requirement no theory provides or two theories both claim, theories that require each other in a cycle, an input parameter no component takes (a misspelled name, usually), a derived parameter nothing can compute.

class cosmofit.core.model.Model(info)[source]

Bases: object

Parameters:

info (dict, str or Path) – The input; see core.info. A sampler block, if any, is ignored here.

rejections: dict[str, int]

Rejected points, by reason.

affected_by(name)[source]

The components whose result changes when the sampled parameter name does: those taking it, or a dependent parameter computed from it, and every component reading one of those.

Parameters:

name (str)

Return type:

set[str]

slow_and_fast()[source]

The sampled parameters split by cost: slow ones change a theory’s inputs, so moving them recomputes it; fast ones reach likelihoods alone – nuisance parameters, mostly – and a move in them is served from every theory’s cache.

Each list keeps sampled_params order.

Return type:

tuple[list[str], list[str]]

logposterior(point, want_derived=True)[source]

Evaluate the model at point (a dict, or an array in sampled_params order).

A point outside the prior is not evaluated. A theory or likelihood that cannot produce a prediction there gives -inf with the reason in rejected, counted in rejections.

Parameters:

want_derived (bool)

Return type:

PosteriorPoint

loglike(point)[source]

sum(ln L) at point, -inf if rejected.

Return type:

float

class cosmofit.core.model.PosteriorPoint(logpost, logprior, loglikes=<factory>, derived=<factory>, rejected=None)[source]

Bases: object

One point’s evaluation.

Parameters:
logpost

logprior + sum(loglikes).

Type:

float

logprior

Normalized log-prior of the sampled parameters.

Type:

float

loglikes

Per likelihood.

Type:

dict[str, float]

derived
Type:

dict[str, float]

rejected

Why the point was rejected, if it was.

Type:

str or None

property chi2: dict

-2 ln L per likelihood, plus "total".

cosmofit.core.model.get_model(info)[source]

Build a Model from an input.

Return type:

Model

Input and registry

The input: a dict, or the YAML file it was written as.

Top-level blocks:

theory:      {name: options}      # what computes predictions
likelihood:  {name: options}      # what compares them with data
params:      {name: declaration}  # see core.parameters
sampler:     {name: options}      # exactly one
output:      path prefix          # optional (used by later phases)
debug, force, resume              # optional flags

Options may be null (desi: on its own line) for “defaults”.

cosmofit.core.info.load_info(source)[source]

An input as a dict: a dict (copied), a path to a .yaml/.yml file, or YAML text.

Return type:

dict

cosmofit.core.info.validate_info(info)[source]

Check an input’s shape and normalize it: every block a dict, every component’s options a dict (None becomes {}).

Raises:

ValueError – Naming the first thing that is wrong.

Parameters:

info (dict)

Return type:

dict

Turning a name in an input into a class.

A theory, likelihood or sampler is named in an input by one of:

  • a built-in name – minimize, legacy_cosmology, or any of the library’s dataset names (desi, pantheon, …), which resolve to the wrapped classes in core.legacy;

  • an import path, package.module:Class or package.module.Class, for a component that lives in someone else’s package;

  • an entry point in the group cosmofit.theories, cosmofit.likelihoods or cosmofit.samplers, so an installed package can register names of its own;

  • the class key of the component’s options, which overrides the name and lets one class be listed twice under different names.

cosmofit.core.registry.resolve(kind, name, info=None)[source]

The class a component name stands for.

Parameters:
  • kind ({"theory", "likelihood", "sampler"})

  • name (str) – The name it is listed under in the input.

  • info (dict, optional) – Its options; a class key there takes precedence over name.

Returns:

type – For a legacy dataset name, core.legacy.LegacyLikelihood.

cosmofit.core.registry.builtin_names(kind)[source]

Every name resolve knows without an import path.

Parameters:

kind (str)

Return type:

list[str]

Running an input end to end.

cosmofit.core.run.run(info, seed=None, callback=None)[source]

Build the model an input describes, run its sampler, and return both.

Parameters:
  • info (dict, str or Path) – The input; it must have a sampler block – or a post block, to reweight a finished run (see core.post).

  • seed (int, optional) – For the sampler’s random draws, unless the input sets one.

  • callback (callable, optional) – Called with a dict of progress (steps, Rminus1 or tau, acceptance, seconds, and the stopping targets) at every check of a sampler that checks – for a progress bar. In the first process only.

Returns:

(dict, Sampler) – The validated input and the sampler that ran – its products() hold the result. For a post input, the Post that ran instead.

Where a run writes what it found, in files other tools read.

An input’s output: chains/run is a prefix. A run writes:

chains/run.input.yaml

The input as given.

chains/run.updated.yaml

The input with every default filled in: each component’s parameters as the run used them, and the sampler’s options.

chains/run.1.txt, chains/run.2.txt, …

The chains, one file per chain, in getdist’s format: a header line of names, then one row per distinct point – weight, minuslogpost, the sampled and derived parameters, then minuslogprior and each likelihood’s chi2__<name>.

chains/run.paramnames, chains/run.ranges

For getdist: each column’s name and LaTeX label (derived ones starred), and each sampled parameter’s prior support.

chains/run.covmat

The proposal covariance the sampler ended with, to start the next run from – or, from fisher, the inverse Fisher matrix.

chains/run.minimum.txt

The best fit minimize (or fisher, before it expands) found, as one row of a chain.

chains/run.profile.txt

A profile likelihood: the fixed values, chi2 minimized over the rest, and where the rest went.

chains/run.evidence.yaml

Nested sampling’s ln Z, its error, and what it was computed with.

A run refuses to write over another’s files unless told what to do with them: force: true deletes them first, resume: true continues from them – and only if the input they were written with is this one.

class cosmofit.core.output.Output(info)[source]

Bases: object

Parameters:

info (dict) – The validated input. Its output prefix, force and resume decide what happens here; without output nothing is written.

existing()[source]

Every file this prefix has written before.

Return type:

list[Path]

prepare()[source]

Make the prefix ready to write. Returns whether this run resumes an earlier one.

Raises:

OutputError – If earlier output is there and neither force nor resume says what to do with it, or if resume finds output written by a different input.

Return type:

bool

write_updated(model, sampler_options)[source]

The input as run, every default filled in.

Parameters:

sampler_options (dict)

Return type:

None

write_getdist_metadata(model, columns)[source]

.paramnames and .ranges.

Parameters:

columns (list[str])

Return type:

None

chain(index, columns)[source]

The index-th chain (1-based), as getdist numbers them.

Parameters:
Return type:

ChainFile

write_table(suffix, names, rows)[source]

Rows under a #-header of names, as the chains are written.

Parameters:
Return type:

None

read_covmat()[source]

(names, covariance) from this prefix, or None.

exception cosmofit.core.output.OutputError[source]

Bases: RuntimeError

An output prefix in a state the run cannot use.

class cosmofit.core.output.ChainFile(path, columns)[source]

Bases: object

One chain on disk, appended to as it grows.

Parameters:
  • path (Path)

  • columns (list[str]) – Column names after weight and minuslogpost.

append(rows)[source]

Rows of weight, minuslogpost, *columns.

Parameters:

rows (ndarray)

Return type:

None

read()[source]

Every row so far, (n, 2 + len(columns)).

Return type:

ndarray

Processes that run one sampler together.

A parallel sampler needs two collective operations from its processes: every process handing something to the first (gather), and the first handing something to all (bcast). Three communicators provide them:

Serial

One process, which is all of them; nothing is sent anywhere.

MPIComm

mpi4py’s COMM_WORLD, for a run started under mpirun: every process runs the same input, and world() hands each its place in it.

PipeComm

Processes this one starts itself, with spawn(), connected by pipes. Started with the spawn method – the only one Windows has, and the safe one everywhere – so each rebuilds the model from the input rather than inheriting it.

A process that fails in a PipeComm sends the failure in place of what it owed, and the first process raises it, so an error in one process stops the run instead of leaving the rest waiting.

class cosmofit.core.mpi.Serial[source]

Bases: object

A run of one process.

class cosmofit.core.mpi.MPIComm(comm)[source]

Bases: object

mpi4py’s COMM_WORLD.

Parameters:

comm (mpi4py.MPI.Comm)

class cosmofit.core.mpi.PipeComm(rank, size, connections, processes=None)[source]

Bases: object

Processes connected by pipes to the first.

Parameters:
  • rank (int)

  • size (int)

  • connections (list) – For the first process, one connection to each of the others, in rank order; for the others, the one connection to the first.

  • processes (list, optional) – The first process’s handles on the others, to tell a process that died from one that is slow.

fail(error)[source]

From a process other than the first: report error and stop.

Parameters:

error (BaseException)

Return type:

None

close()[source]

From the first process: stop the others.

Return type:

None

cosmofit.core.mpi.world()[source]

The communicator this process runs in: MPIComm when started under mpirun with more than one process and mpi4py installed, Serial otherwise.

cosmofit.core.mpi.spawn(size, target, args=())[source]

Start size - 1 processes, each calling target(comm, *args) with its own PipeComm, and return the first process’s.

target and args must pickle: the new processes import target by name and rebuild everything else from args.

Parameters:
Return type:

PipeComm

exception cosmofit.core.mpi.WorkerError[source]

Bases: RuntimeError

A process of a parallel run failed; the message is its traceback.

exception cosmofit.core.mpi.Aborted[source]

Bases: RuntimeError

Raised in the processes that did not fail, when another one did.

Importance reweighting: a finished run’s samples, re-weighted for a changed posterior – a likelihood added or taken away – and given new derived parameters, without sampling again.

output: chains/lcdm            # the run to start from
post:
  suffix: bbn                  # writes chains/lcdm.post.bbn.*
  skip: 0.3                    # burn-in to drop, by weight per chain
  thin: 1
  add:
    likelihood: {external.bbn: }
    params: {S8: {derived: true}}
  remove:
    likelihood: [sn.pantheonplus]

Every kept sample is evaluated once on the new model, and its weight multiplied by L_new / L_old: the ratio of the new likelihood to the one it was sampled from, which the chain’s own chi2__ columns record. The priors of the sampled parameters cannot change, nor can parameters be added to or taken from the sampled set – the samples say nothing about a direction that was never explored.

Reweighting is only as good as the overlap. When the new posterior is much narrower than the old, or sits in its tail, a few samples carry all the weight; products() reports the effective sample size before and after, (sum w)^2 / sum w^2, and a collapse is warned about. Sample again rather than trust it.

The result is written like a run’s own output, under the prefix <output>.post.<suffix>: chains in getdist’s format, one per input chain, .paramnames, .ranges and .updated.yaml (the new input), which getdist reads as any other run.

class cosmofit.core.post.Post(info)[source]

Bases: object

Parameters:

info (dict) – output (the run’s prefix), post (see the module docstring) and optionally force.

Raises:

PostError – Before anything is evaluated, for an input that cannot apply.

products()[source]

samples and their new weights (largest 1), each chain’s rows under chains with their columns; n_samples read and n_rejected by the new model; the effective sample size ess_before and ess_after.

Return type:

dict

exception cosmofit.core.post.PostError[source]

Bases: ValueError

A post-processing input that cannot be applied to its run.

The existing models and datasets

The existing models and datasets, as components of the new core.

Temporary by design. LegacyCosmology wraps a Cosmology subclass as a theory; LegacyLikelihood wraps any dataset in DATASET_REGISTRY as a likelihood. Together they let the new core run every model and dataset the library has today, through exactly the code Fitter runs – so the two can be compared point by point, and every later port (a model rewritten as a native theory, a dataset as a native likelihood) has a reference it must reproduce.

In an input, a dataset name is enough to reach these:

theory:
  legacy_cosmology: {model: CPL, compute_rd: true}
likelihood:
  desi: {version: desi2025}
  pantheon:

Every parameter of the model’s parameter class – cosmological and nuisance alike (MB, A_planck), since the old likelihoods read those off the cosmology – is an input of the theory; any not declared in params keeps the class default, as with Fitter.

class cosmofit.core.legacy.LegacyCosmology(info=None, name=None)[source]

Bases: Theory

A Cosmology subclass as a theory.

Options

modelstr or type

"LCDM", "CPL", …, an import path, or the class.

compute_rdbool

Compute rd from the densities, as Fitter(compute_rd=True). rd is then not an input.

derive_sigma8bool

Take sigma8 from the Boltzmann code, as Fitter(derive_sigma8=True). sigma8 is then not an input.

Provides

cosmology (the live object the wrapped likelihoods read), E, H, DM, DH, DV, DA (each z=...), rd, fsigma8 (z=...).

Derived parameters: rd_computed and z_drag.

cache_size: int = 1

One mutable cosmology object, so one state.

initialize()[source]

Set up from self.info. Override; called by __init__.

Return type:

None

accepts(name)[source]

Whether this component takes the input parameter name. Defaults to the names in params.

Parameters:

name (str)

Return type:

bool

get_can_provide()[source]

Quantities this theory can compute.

Return type:

list[str]

get_derived_params()[source]

Names of the derived parameters this component can output.

Return type:

list[str]

initialize_complete()[source]

Called once every component has its provider. For setup that must wait for other components to be ready.

Return type:

None

calculate(state, want_derived=True, **params)[source]

Compute everything requested at params into state. Return False if the parameters admit no solution (the point is then rejected, not an error).

Parameters:
Parameters:
  • info (dict | None)

  • name (str | None)

class cosmofit.core.legacy.LegacyLikelihood(info=None, name=None)[source]

Bases: Likelihood

A dataset of DATASET_REGISTRY as a likelihood: ln L = -chi2 / 2 of the wrapped class.

Options

datasetstr, optional

Registry key; defaults to the name the likelihood is listed under, so desi: in an input is enough.

Any other option is passed to the wrapped class’s constructor (version, marginalize_MB, include_cepheid, …).

initialize()[source]

Set up from self.info. Override; called by __init__.

Return type:

None

get_requirements()[source]

What this component needs from theories: {quantity: options or None}.

Return type:

dict

initialize_with_provider(provider)[source]

Called once every component exists and requirements are resolved, with the provider this component reads through.

Return type:

None

logp(**params)[source]

ln L at the current point. params are this likelihood’s own input parameters (its nuisance parameters, say).

Return type:

float

check_model(model)[source]

The dataset-combination warnings Fitter gives, once per model (from whichever wrapped likelihood is listed first).

Return type:

None

Parameters:
  • info (dict | None)

  • name (str | None)

From the 1.x interface to the 2.0 core.

stats.fitter.Fitter.to_info() writes a fitter as an input the new core runs (cosmofit.core): the same model, datasets, free parameters and bounds, fixed values and dataset options. With a sampler block added and written to YAML, cosmofit run takes over from it. It is written one of two ways.

to_info(): the analysis in 2.0

The native theories and likelihoods. The model becomes its dark sector on the background theory (CPL is dark_energy: cpl), with radiation and the massive neutrinos’ own history in E(z); the datasets become their native likelihoods (desi is bao.desi, see data.metadata). That is the same analysis on the new physics, not the fitter’s numbers: with radiation in the late-time expansion, chi2 moves by a few hundredths to about one – 0.4 to 1.1 for LCDM on CC + DESI + Pantheon+ near the best fit, most of it the supernovae. That is all radiation: with radiation: false the native input gives the fitter’s chi2 to 1e-7. Four parameters are named differently there – the generalized Chaplygin gas’s A_s and alpha are A_gcg and alpha_gcg, the power-law f(T)’s n is n_ft, Hu-Sawicki’s n is n_hs – and are renamed.

A model defined at runtime or outside the library has no native sector; it is wrapped by the legacy one, radiation off, which reproduces its expansion exactly but cannot give the sound horizon its radiation era – compute_rd and the CMB distance priors are refused there, and exact=True is the way.

to_info(exact=True): the fitter’s numbers

The legacy_cosmology theory and the old dataset names (core.legacy): the fitter’s own model and likelihood classes, run by the new core. chi2 is the fitter’s at every point, for every model and dataset – the reference to compare the native input against.

The parameters, either way

Each free one gets its bounds as a uniform prior, its initial value as the centre of a narrow ref, and a hundredth of its range as a proposal. Fixed values are written for every parameter some component takes; the ones nothing takes (the fitter carries every model’s full parameter set) are left out.

cosmofit.compat.fitter_to_info(fitter, exact=False)[source]

The input for the new core equivalent to fitter: on the native theories (the default), or through the fitter’s own classes (exact=True). See the module docstring.

Raises:

ValueError – For a free parameter no component takes – one the model derives, which the fitter samples to no effect – or, natively, for a model outside the library with compute_rd.

Parameters:

exact (bool)

Return type:

dict

cosmofit.compat.RENAMED = {'FRHuSawicki': {'n': 'n_hs'}, 'FTPowerLaw': {'n': 'n_ft'}, 'GCG': {'A_s': 'A_gcg', 'alpha': 'alpha_gcg'}}

Old parameter names the native sectors spell differently, by model.

class cosmofit.compat.CoreChains(chain, log_prob, acceptance, stopped_by, output=None)[source]

Bases: object

The core’s chains, wearing the part of emcee.EnsembleSampler that Fitter and its figures read: get_chain, get_log_prob, get_autocorr_time, nwalkers, iteration, acceptance_fraction.

Each Metropolis-Hastings chain is one “walker”: its weighted rows are expanded back into one row per step, and every chain takes the same number of steps, so together they are an array of (steps, chains, parameters) exactly as an ensemble’s walkers are. emcee’s walkers come back as they were.

Parameters:
  • chain (ndarray) – (steps, walkers, parameters).

  • log_prob (ndarray) – (steps, walkers).

  • acceptance (array_like) – Per walker.

  • stopped_by (dict) – The sampler’s own stopping rule: rule, value, target and whether it was met (converged). convergence() reports that rather than its own rule, which is emcee’s.

  • output (str or None) – The prefix the core wrote the run under.

reused

Whether a saved run was read back without a new step.

classmethod from_sampler(sampler, output=None)[source]

From a finished mcmc or emcee sampler of the core.

Return type:

CoreChains

cosmofit.compat.sample_on_core(fitter, sampler='mcmc', options=None, *, output=None, seed=None, callback=None, burn_in=0.3)[source]

Sample fitter’s posterior with the core’s mcmc or emcee sampler, and make the result the fitter’s own: fitter.sampler becomes a CoreChains, so summary(), convergence(), best_fit() and every figure read it as they read emcee.

With output, the run is written there in getdist’s format, and a run already there is continued – or, if it had met its stopping rule, read back without a single new step.

Parameters:
  • burn_in (float) – For mcmc, the fraction of each chain’s steps discarded as burn-in. emcee discards two autocorrelation times.

  • sampler (str)

  • options (dict | None)

  • output (str | None)

  • seed (int | None)

Returns:

The core’s sampler, for its own products.

cosmofit.compat.profile_on_core(fitter, name, values)[source]

profile(), by the core’s profile sampler: name, values, chi2, delta_chi2 and params (a dict per value, as the fitter returned them). Starts from the fitter’s best fit when it has one, and minimizes without gradients when a Boltzmann code’s noise would defeat them.

Parameters:

name (str)

Return type:

dict

cosmofit.compat.fisher_on_core(fitter, point=None)[source]

fisher(), by the core’s fisher sampler: at point, else the fitter’s best fit, else at a best fit found first. Returns the fitter’s keys – matrix, covariance, errors (an array), theta, steps, free_params, positive_definite – and the core’s unstable_steps.

Parameters:

point (dict | None)

Return type:

dict

cosmofit.compat.evidence_on_core(fitter, nlive=400, dlogz=0.05, seed=42)[source]

stats.nested.run_nested(), by the core’s nested sampler, returned as the same NestedResult, so stats.evidence.bayes_factor() compares it as before.

Parameters:

The command line

The cosmofit command.

cosmofit run input.yaml [--output PREFIX] [--force | --resume] [--seed N]
cosmofit list [theory | likelihood | sampler]
cosmofit doc NAME
cosmofit gui [streamlit options]

run runs an input: its sampler, or – for an input with a post block – the reweighting of a finished run (core.post). Under mpirun -n 4 cosmofit run input.yaml the mcmc sampler shares its chains between the four processes. What the run found is summarized on the terminal; everything it found is in the output prefix.

list names every component an input can use without an import path: the built-in ones and those installed packages register under the cosmofit.theories, cosmofit.likelihoods and cosmofit.samplers entry points.

doc shows what one of them is: its description, the options it takes, the parameters it brings with their default declarations, and what it provides or requires – the starting point for writing it into an input.

gui starts the graphical interface (cosmofit.gui); what follows it goes to streamlit run.

python -m cosmofit is the same command.

cosmofit.cli.main(argv=None)[source]

Entry point of the cosmofit command; returns the exit status.

Return type:

int

Samplers

Samplers of the new core (see cosmofit.core).

evaluate

The model at one point: log-prior, every chi2, every derived value.

minimize

The maximum of the posterior or the likelihood, in scaled coordinates, from one or more starts.

profile

A profile likelihood: one parameter fixed at each of a list of values, the others minimized over.

fisher

The curvature at the best fit, with steps chosen by the likelihood, and its inverse as a Gaussian approximation to the posterior.

mcmc

Adaptive Metropolis-Hastings, stopped by the Gelman-Rubin R - 1, writing getdist-format chains.

emcee

emcee’s affine-invariant ensemble, stopped by the autocorrelation time.

nested

dynesty’s nested sampling: the evidence, and weighted samples.

What every sampler of the new core shares.

class cosmofit.samplers.base.Sampler(info, model, seed=None, output=None)[source]

Bases: object

Base sampler.

Parameters:
  • info (dict) – The sampler’s options from the input.

  • model (core.model.Model) – The model to sample.

  • seed (int, optional) – Seeds rng. An info["seed"] takes precedence.

  • output (core.output.Output, optional) – Where to write; nothing is written without one.

Notes

Subclasses read their options in initialize(), do the work in run(), and return what they found from products().

A sampler that cannot pick up where an earlier run stopped leaves resumable false, and is refused resume: true.

defaults: dict = {}

Options this sampler takes, with defaults.

resumable: bool = False

Whether resume: true can continue an earlier run’s output.

parallel: bool = False

Whether this sampler shares a run between processes under mpirun. One that does not is refused there, rather than run once per process into the same output.

callback

Called with a dict of progress at every check, by the samplers that check (mcmc, emcee); see core.run.run().

initialize()[source]

Read options. Override.

Return type:

None

class cosmofit.samplers.base.ChainColumns(model)[source]

Bases: object

The columns of a chain row after weight and minuslogpost: the sampled parameters, the derived ones not dropped, minuslogprior, and each likelihood’s chi2__<name> (dots as underscores).

Parameters:

model (core.model.Model)

of(x, result)[source]

x and its evaluation, in columns order.

Return type:

ndarray

Evaluate the model at one point and report everything about it.

The first thing to run on a new input: it builds the model, evaluates it once, and shows the log-prior, every likelihood’s chi2 and every derived parameter – without sampling anything.

class cosmofit.samplers.evaluate.Evaluate(info, model, seed=None, output=None)[source]

Bases: Sampler

Options

overridedict, optional

Values for sampled parameters. The rest are taken at their ref (or, failing that, their prior’s center).

defaults: dict = {'override': None}

Options this sampler takes, with defaults.

initialize()[source]

Read options. Override.

Return type:

None

Parameters:
  • info (dict | None)

  • seed (int | None)

The maximum of the posterior (or of the likelihood), found by optimization.

Two things here that the old Fitter.best_fit did not do:

It works in scaled coordinates. Each parameter is optimized as (theta - center) / scale, with the scale its proposal width, its ref width or its prior’s – so H0 ~ 70 and omega_b ~ 0.02 both move by order one per unit step. A finite-difference gradient and an initial simplex then mean the same thing for every parameter.

It maximizes the posterior by default. With a Gaussian prior on a parameter, the maximum-likelihood point and the MAP differ, and they are different questions. ignore_prior: true asks the maximum-likelihood one (the prior’s support still bounds the search).

With an output prefix the best point is written to .minimum.txt, as one row in the chains’ format.

class cosmofit.samplers.minimize.Minimize(info, model, seed=None, output=None)[source]

Bases: Sampler

Options

methodstr

Any scipy.optimize.minimize method; default "L-BFGS-B". "Nelder-Mead" and "Powell" need no gradient.

startsint

Independent starting points: the first at the ref centers, the rest drawn from ref (or the prior). The best is kept.

ignore_priorbool

Maximize the likelihood instead of the posterior.

max_evalsint, optional

Evaluation budget per start (maxfun/maxfev).

tolfloat, optional

Passed to scipy.optimize.minimize.

polishbool

After a gradient-based method, go on from where it stopped with Nelder-Mead and keep the better of the two. Default True.

defaults: dict = {'ignore_prior': False, 'max_evals': None, 'method': 'L-BFGS-B', 'polish': True, 'starts': 1, 'tol': None}

Options this sampler takes, with defaults.

initialize()[source]

Read options. Override.

Return type:

None

Parameters:
  • info (dict | None)

  • seed (int | None)

Adaptive Metropolis-Hastings, stopped by the Gelman-Rubin statistic.

Several chains run side by side, each a Gaussian random walk with the optimal scaling (2.4 / sqrt(d))^2 times a proposal covariance. That covariance starts from a covmat file if given (the one the previous run ended with, say), else from each parameter’s proposal – or its ref or prior width – and is learned: once the chains roughly agree, it is replaced by their pooled covariance, which is what makes a random walk efficient on a correlated posterior.

Every learn_every steps the chains are compared. With the second half of each chain, R - 1 is the largest eigenvalue of W^-1 B: the spread of the chains’ means (B) in units of the covariance within them (W), the multivariate form of Gelman & Rubin’s statistic (Brooks & Gelman 1998). Sampling stops once it falls below Rminus1_stop. A single chain is compared with itself, split into four.

The chains are weighted: a point the walk stayed at for n steps is one row of weight n, as getdist reads them.

Fast and slow parameters

A parameter that reaches only likelihoods – a nuisance parameter like MB or A_planck – is fast: moving it leaves every theory’s inputs alone, so the theories answer from their caches and a step costs a likelihood evaluation. One that changes a theory’s inputs is slow. core.model.Model.slow_and_fast() makes the split.

When there are both, each step is a slow move followed by fast_steps fast ones. The proposal is blocked the way the covariance is: with the parameters ordered slow first, its Cholesky factor L gives a slow move L[:, slow] z – which also shifts the fast parameters along their correlation with the slow ones – and a fast move L[fast, fast] z, a step in the fast parameters’ distribution given the slow ones. Each block is scaled by proposal_scale / sqrt(its dimension). Every fast move is an ordinary Metropolis step, so the target is unchanged; the walk simply spends its effort where effort is cheap.

drag: true uses the fast moves differently, for Neal’s (2005) dragging: a slow proposal is not accepted or rejected on its own, but after the fast parameters have been moved fast_steps - 1 times along a path of distributions interpolating between the current slow point and the proposed one, so the fast parameters can adjust to the new slow ones before the decision. On a posterior where the fast parameters are strongly tied to the slow ones that raises the slow acceptance; it costs two evaluations per fast step, and needs every theory to cache at least two states.

fast_steps defaults to (t_slow / t_fast) ** oversample_power, from timing the starting point – 0.4, as in CosmoMC and cobaya. Give it as a number for a run that repeats exactly under its seed.

Several processes

The chains can run in separate processes: processes: n starts them here (see core.mpi), and a run under mpirun shares them between the processes it was given. The processes meet only at each check, where the first gathers every chain’s second half, decides R - 1 and the covariance, and hands both back.

Every chain draws from its own random stream, spawned from the run’s seed, so the split changes nothing: a run in four processes writes the same chains, byte for byte, as in one. Starting a process rebuilds the model and reloads its data, which takes seconds; it pays when an evaluation is slow – a Boltzmann code’s, not a distance likelihood’s.

class cosmofit.samplers.mcmc.MCMC(info, model, seed=None, output=None)[source]

Bases: Sampler

Options

chainsint

Chains run side by side; at least two to compare. Default 4.

max_samplesint

Steps per chain before giving up on convergence. Default 100000.

Rminus1_stopfloat

Stop once R - 1 is below this. Default 0.01.

learn_proposalbool

Learn the proposal covariance from the chains. Default True.

learn_proposal_Rminus1_maxfloat

Learn only once R - 1 is below this – before then the chains have not found the posterior yet. Default 2.

learn_everyint or str

Steps per chain between checks; "40d" is 40 times the number of sampled parameters (the default).

covmatstr or None

A covariance file to start the proposal from (# names header, then the matrix); parameters it lacks keep their own width.

proposal_scalefloat

The walk’s step in units of sqrt(covariance / d). Default 2.4.

max_triesint

Consecutive rejected proposals before a chain is declared stuck. Default 10000.

max_timefloat or None

Seconds before stopping, converged or not.

oversample_powerfloat

Fast moves per slow one, as a power of their cost ratio. Default 0.4; 0 makes one of each.

fast_stepsint or None

Fast moves per slow one, overriding oversample_power.

dragbool

Drag the fast parameters along each slow proposal instead of oversampling them. Default False.

processesint

Processes to run the chains in, started here; ignored under mpirun, which decides that itself. Default 1.

resumable: bool = True

Whether resume: true can continue an earlier run’s output.

parallel: bool = True

Whether this sampler shares a run between processes under mpirun. One that does not is refused there, rather than run once per process into the same output.

defaults: dict = {'Rminus1_stop': 0.01, 'chains': 4, 'covmat': None, 'drag': False, 'fast_steps': None, 'learn_every': '40d', 'learn_proposal': True, 'learn_proposal_Rminus1_max': 2.0, 'max_samples': 100000, 'max_time': None, 'max_tries': 10000, 'oversample_power': 0.4, 'processes': 1, 'proposal_scale': 2.4}

Options this sampler takes, with defaults.

initialize()[source]

Read options. Override.

Return type:

None

products(skip=0.0)[source]

samples (sampled parameters), weights and minuslogpost of every chain together, each chain’s rows under chains, the columns of those rows, the final Rminus1, whether it converged, the acceptance rate, the proposal covmat, and the progress of every check.

skip drops that fraction of each chain’s weight from its start – the burn-in, as getdist’s ignore_rows does. The files keep every sample.

Parameters:

skip (float)

Return type:

dict

Parameters:
  • info (dict | None)

  • seed (int | None)

cosmofit.samplers.mcmc.gelman_rubin(chains)[source]

Multivariate R - 1 of weighted chains [(x, w), ...]: the largest eigenvalue of W^-1 B, with W the mean covariance within chains and B the covariance of their means.

Parameters:

chains (list[tuple[ndarray, ndarray]])

Return type:

float

A profile likelihood: one parameter held at each of a list of values, chi2 minimized over all the others.

The honest tool where Wilks’ theorem does not apply, and how a parameter against a boundary should be reported – a marginal posterior smooths over a cliff that a profile shows (LsCDM’s z_dagger has a 28-unit one).

It maximizes the likelihood by default (ignore_prior: true): a profile is a frequentist object, and the prior’s support only bounds the search.

Neighbouring values differ by one small step in one parameter, so their optima are close; warm_start starts each from the last one’s solution, which costs a fraction of a cold start. Turn it off where the surface may have a discontinuity the walk could be trapped on the wrong side of, or give starts above one.

With an output prefix the profile is written to .profile.txt: the value, chi2, delta_chi2 from the profile’s minimum, then the other parameters where the minimization left them.

class cosmofit.samplers.profile.Profile(info, model, seed=None, output=None)[source]

Bases: Minimize

Options

paramstr

The sampled parameter to profile.

valueslist or dict

Values to hold it at: a list, or {min, max, n} for n evenly spaced ones.

warm_startbool

Start each value from the previous one’s optimum. Default True.

method, starts, max_evals, tol

As for minimize.

ignore_priorbool

Default True: profile the likelihood.

defaults: dict = {'ignore_prior': True, 'max_evals': None, 'method': 'L-BFGS-B', 'param': None, 'polish': True, 'starts': 1, 'tol': None, 'values': None, 'warm_start': True}

Options this sampler takes, with defaults.

initialize()[source]

Read options. Override.

Return type:

None

products()[source]

param, values, chi2 (-2 times the maximized log-likelihood, or log-posterior with ignore_prior: false), delta_chi2 from the smallest, params (each sampled parameter’s value along the profile), and success per value.

Return type:

dict

Parameters:
  • info (dict | None)

  • seed (int | None)

The Fisher matrix: the curvature of chi2 at the best fit, and its inverse as a Gaussian approximation to the posterior.

F_ij = (1/2) d^2 chi2 / d theta_i d theta_j, by central differences – a forward difference would inherit a first-derivative error, and at the minimum the first derivative is what is supposed to vanish. It costs ~2 d^2 evaluations where an MCMC costs thousands per parameter, which is the reason to have it for a likelihood whose every evaluation runs a Boltzmann code. It is only an approximation: good for near-elliptical contours, poor for a parameter against a prior edge or a posterior with a plateau.

What the old Fitter.fisher got wrong, and this does not:

The step is chosen by the likelihood, not by the prior. A step of 1e-3 of the prior width is far too small for a likelihood with numerical noise (CAMB’s is enough to swamp it) and needlessly arbitrary for the rest. Here each parameter’s step is found so that it moves chi2 by about one – one conditional standard deviation – starting from the parameter’s scale and correcting by the measured curvature. That is large against any noise and small enough for the quadratic approximation where one holds at all. A fixed step (in units of each parameter’s scale) is still available.

The step is tested. The diagonal is recomputed at half the steps; an entry that moves by more than 10% means the quadratic approximation does not hold there, and is warned about.

The result is checked before it is inverted. A matrix that is not positive definite is not the curvature at a minimum – the point is not the best fit, or a direction is flat. The worst direction is named, the pseudo-inverse is returned, and the error of a parameter it leaves without a positive variance is NaN. Only a positive-definite inverse is written to .covmat, where an MCMC can start from it.

class cosmofit.samplers.fisher.Fisher(info, model, seed=None, output=None)[source]

Bases: Sampler

Options

pointdict, optional

Where to expand, every sampled parameter by name. Without it the best fit is found first, by minimize with the options under minimize.

minimizedict, optional

Options for that minimization (method, starts, …).

ignore_priorbool

Expand -2 ln L rather than -2 ln posterior. Default False.

step“auto” or float

"auto" (the default) finds each parameter’s step from the likelihood; a number is a fixed step in units of each parameter’s scale (proposal, ref width or prior width).

check_stepbool

Recompute the diagonal at half the steps and warn if it moves. Default True; 2 d more evaluations.

defaults: dict = {'check_step': True, 'ignore_prior': False, 'minimize': None, 'point': None, 'step': 'auto'}

Options this sampler takes, with defaults.

initialize()[source]

Read options. Override.

Return type:

None

products()[source]

point and the chi2 there, the Fisher matrix and its inverse covariance (in names order, parameter units), errors, the steps used, whether the matrix was positive_definite, the parameters whose step test failed (unstable_steps) and n_evaluations.

Return type:

dict

Parameters:
  • info (dict | None)

  • seed (int | None)

emcee’s affine-invariant ensemble sampler, on the new core.

Walkers move together, each proposing along the line to another, so the sampler is insensitive to linear correlations without learning a covariance – the alternative to adaptive Metropolis-Hastings when the posterior is cheap and a proposal is not worth tuning.

The walkers are not independent chains, so convergence is not judged by comparing them. It is judged by the integrated autocorrelation time tau (Goodman & Weare 2010; emcee’s integrated_time): sampling stops once the run is tau_factor times longer than the largest tau, and tau itself has stopped moving by more than tau_rtol between checks – an estimate that is still growing is an underestimate.

Every step of every walker is one row of weight 1 in .1.txt, step by step, so getdist’s ignore_rows drops the first steps of all the walkers together. The last walkers rows are where the walkers stand, which is all resume: true needs.

class cosmofit.samplers.emcee.Emcee(info, model, seed=None, output=None)[source]

Bases: Sampler

Options

walkersint, optional

Default max(32, 4 d); at least 2 d.

max_samplesint

Steps per walker before giving up on convergence. Default 20000.

check_everyint

Steps between convergence checks (and writes). Default 200.

tau_factorfloat

Stop once the run is this many autocorrelation times long. Default 50.

tau_rtolfloat

…and tau changed by less than this since the last check. Default 0.01.

movesstr

"stretch" (the default) or "de" (differential evolution, for strongly correlated posteriors).

max_triesint

Draws from ref allowed per walker for a finite start.

max_timefloat or None

Seconds before stopping, converged or not.

resumable: bool = True

Whether resume: true can continue an earlier run’s output.

defaults: dict = {'check_every': 200, 'max_samples': 20000, 'max_time': None, 'max_tries': 1000, 'moves': 'stretch', 'tau_factor': 50.0, 'tau_rtol': 0.01, 'walkers': None}

Options this sampler takes, with defaults.

initialize()[source]

Read options. Override.

Return type:

None

products(skip=None)[source]

samples (sampled parameters) and weights of every walker together, the same rows under chains (one chain), their columns, the autocorrelation time tau, whether it converged, the mean acceptance and the progress of every check.

skip drops that fraction of the steps from the start; by default 2 tau steps, the burn-in emcee’s authors recommend.

Parameters:

skip (float | None)

Return type:

dict

Parameters:
  • info (dict | None)

  • seed (int | None)

Nested sampling with dynesty: the Bayesian evidence, and posterior samples on the way.

The tool for comparisons a likelihood-ratio test cannot make – LsCDM against LCDM, reached only as z_dagger -> infinity, or DGP, which is not nested at all. Read stats.evidence on prior sensitivity before quoting a Bayes factor: ln Z moves with the prior’s width, so every prior here enters the evidence, and a comparison is only as meaningful as the priors are.

Every prior kind is supported, through its inverse CDF: the unit cube is mapped parameter by parameter, so a Gaussian prior is a Gaussian prior here too and not the box around it.

The dead points are written to .1.txt with their posterior weights – getdist reads unequal weights as they are – and ln Z with its error to .evidence.yaml. A run cannot be resumed.

class cosmofit.samplers.nested.Nested(info, model, seed=None, output=None)[source]

Bases: Sampler

Options

nliveint

Live points; the evidence error goes roughly as sqrt(information / nlive). Default 500.

dlogzfloat

Stop once the estimated remaining evidence is below this. Default 0.05.

bound, samplestr

dynesty’s bounding and sampling methods. Defaults "multi" and "auto".

max_callsint, optional

Likelihood evaluations before stopping.

defaults: dict = {'bound': 'multi', 'dlogz': 0.05, 'max_calls': None, 'nlive': 500, 'sample': 'auto'}

Options this sampler takes, with defaults.

initialize()[source]

Read options. Override.

Return type:

None

products()[source]

log_evidence and log_evidence_error; the information (prior-to-posterior KL divergence, nats) and the Bayesian model dimensionality 2 Var[ln L] (Handley & Lemos 2019); the weighted samples, their weights (largest 1) and the same as rows under chains with their columns; nlive and n_evaluations.

Return type:

dict

Parameters:
  • info (dict | None)

  • seed (int | None)

Native theories

Native theories of the 2.0 core.

background

Background – the expansion history, radiation and massive neutrinos included, with any dark sector from DARK_SECTORS.

early_universe

EarlyUniverse – the sound horizon at the drag epoch and at recombination, from the background’s own expansion.

growth

Growth – the linear growth factor, growth rate and f sigma8, on the background’s expansion and through the dark sector’s growth hooks.

camb

CAMB – CMB spectra and sigma8 from CAMB, for dark sectors it can represent (cmb_support()).

Named in an input’s theory block by these names.

Dark sectors, by family:

  • dark energy on top of GR (theories.dark_energy): lambda, wcdm, cpl, jbp, ba, logarithmic, pede, gede, lscdm, gcg, ide;

  • modified Friedmann equations (theories.modified_gravity): dgp, cardassian, fq_exponential, ft_power_law, frt_linear;

  • the holographic family (theories.holographic): hde, ade, rde;

  • the running vacuum (theories.running_vacuum): rvm;

  • any old-style model, without radiation (theories.legacy_expansion): legacy.

The expansion history, with everything in it.

The old models each wrote out E(z)^2 = Omega_m (1+z)^3 + Omega_k (1+z)^2 + Omega_de(z) – no photons, no neutrinos – and the parts of the library that could not do without radiation built their own: the CMB distance priors one way, the sound horizon another. Three expansion histories for one cosmology, agreeing only where radiation did not matter.

Here there is one:

E(z)^2 = [omega_gamma a^-4 + omega_nu(a) + omega_cb a^-3] / h^2
         + Omega_k a^-2 + Omega_de f(z)

with photons from T_CMB, neutrinos with their exact Fermi-Dirac density (one massive species carrying m_nu, as CAMB’s default), and the dark energy’s f(z) = rho_de(z)/rho_de(0) from theories.dark_energy. Omega_de closes the budget, radiation included. Every downstream quantity – distances, the sound horizon, the growth of structure – reads this one E(z).

Options

dark_energystr or dict

"lambda" (default), "wcdm", "cpl", … – see DARK_ENERGY.

parameterization{“fractional”, “physical”}

"fractional" (default): H0, Omega_m, Omega_b, with Omega_m counting massive neutrinos as matter today – the library’s long-standing convention. "physical": H0, omega_b, omega_cdm, the densities a CMB fit samples.

radiationbool

Default True. False drops photons and neutrinos and treats Omega_m as pure (1+z)^3 matter: the old models’ expansion history, exactly, for comparison with them.

zmaxfloat

Initial range of the distance table (default 5). It extends itself when asked for more.

class cosmofit.theories.background.Background(info=None, name=None)[source]

Bases: Theory

The background expansion; see the module docstring.

Provides

E, H [km/s/Mpc], comoving_distance, DM, DH, DV, DA [Mpc] (each z=...), w and Omega_de_z (z=...), and background_densities – the physical densities, for the early-universe and growth theories.

Derived parameters

h, Omega_m, Omega_b, omega_b, omega_cdm, omega_m, Omega_de, Omega_nu (massive, today), Omega_r (photons and massless neutrinos, today), age [Gyr].

initialize()[source]

Set up from self.info. Override; called by __init__.

Return type:

None

get_default_params()[source]

Default declarations for parameters this component owns, overridden by the input’s params. params unless a component’s defaults depend on its options.

Return type:

dict

accepts(name)[source]

Whether this component takes the input parameter name. Defaults to the names in params.

Parameters:

name (str)

Return type:

bool

get_required_params()[source]

Input parameters this component cannot run without. Assembly fails, naming them, if the input does not provide them.

Return type:

list[str]

get_can_provide()[source]

Quantities this theory can compute.

Return type:

list[str]

get_derived_params()[source]

Names of the derived parameters this component can output.

Return type:

list[str]

check_model(model)[source]

Called last, with the assembled Model, for checks that need to see the whole of it – which datasets are combined, which parameters are sampled. Warn or raise here.

Return type:

None

calculate(state, want_derived=True, **p)[source]

Compute everything requested at params into state. Return False if the parameters admit no solution (the point is then rejected, not an error).

Parameters:
get_w(z)[source]

The dark energy’s equation of state – for sectors that have one (a fluid on top of general relativity). A modified Friedmann equation has no w; its effective dark density is get_Omega_de_z().

get_Omega_de_z(z)[source]

Everything in E^2 beyond the standard fluids and curvature, in units of today’s critical density: the dark energy’s density, or for a modified Friedmann equation the effective one a GR analysis would attribute its expansion to.

get_expansion()[source]

The dark sector and what it was solved with – for the growth theory, whose hooks live on the sector.

Return type:

dict

get_background_jumps()[source]

Redshifts at which E(z) is discontinuous.

Return type:

tuple

Parameters:
  • info (dict | None)

  • name (str | None)

cosmofit.theories.background.neutrino_density(a, N_eff, m_nu, omega_gamma=2.4729753286336536e-05)[source]

Total neutrino density omega_nu(a) (massless plus massive) in units of the critical density for H = 100 km/s/Mpc, as it enters H(a)^2.

One massive species carries the whole of m_nu when it is positive; the remaining N_eff - 3.044/3 effective species are massless.

Parameters:
cosmofit.theories.background.neutrino_pressure(a, N_eff, m_nu, omega_gamma=2.4729753286336536e-05)[source]

Total neutrino pressure, in the units of neutrino_density(), from the continuity equation p = -rho - (1/3) d rho / d ln a – a third of the density while relativistic, falling to zero as the massive species slows down.

Parameters:

What a model adds to the standard fluids, and the context it is given.

Background owns the standard content of the universe – cold matter, photons, neutrinos – and curvature. A dark sector turns that into an expansion history: it receives an ExpansionContext holding the standard fluids’ density and pressure as functions of redshift, and returns E(z)^2.

How it does that is the model’s business:

  • a dark energy on top of general relativity adds Omega_de f(z) (theories.dark_energy);

  • a modified Friedmann equation maps the fluids’ density onto E^2 some other way (theories.modified_gravity);

  • a holographic or Ricci dark energy, or a running vacuum, solves an ODE for it (theories.holographic, theories.running_vacuum).

Every one of them sees all the standard fluids, radiation included, through the context – which is what lets one background carry photons and neutrinos for every model without each model writing them out.

class cosmofit.theories.dark_sector.DarkSector[source]

Bases: object

A model’s contribution to the expansion.

Declared through class attributes: name; params, the parameters it requires; defaults, optional parameters with their default values; flat_only, defined for Omega_k = 0 only; radiation_ok, has a form with radiation (False for a wrapped model that only ever had E(z) without it); and derives_matter, fixes the cold-matter density itself, so the background does not take Omega_m (or omega_cdm).

solve(ctx, **p)[source]

E(z)^2 as a function, for this context and these parameters, or None where the model has no solution.

Parameters:

ctx (ExpansionContext)

Return type:

Callable | None

matter_density(make_context, **p)[source]

For derives_matter sectors: today’s cold-matter density Omega_cb, given make_context(Omega_cb).

Parameters:

make_context (Callable)

Return type:

float

jumps(**p)[source]

Redshifts at which E(z) is discontinuous.

Return type:

tuple

clustering_matter(z, growth, **p)[source]

Density of the matter that clusters, in units of today’s critical density. Cold matter by default: massive neutrinos free-stream on the scales growth data measure.

Parameters:

growth (GrowthContext)

matter_exchange(z, growth, **p)[source]

psi = Q / (H rho_m), energy gained by clustering matter per Hubble time – None for conserved matter.

Parameters:

growth (GrowthContext)

mu(z, k, growth, **p)[source]

G_eff / G_N at wavenumber k [h/Mpc] – None for general relativity.

Parameters:
class cosmofit.theories.dark_sector.ExpansionContext(rho_std, p_std, rho_cb, rho_rel, p_rel, rho_std0, rho_rel0, Omega_cb, Omega_k, radiation, H0=70.0)[source]

Bases: object

The standard content of the universe, in units of today’s critical density.

Parameters:
rho_std, p_std

Density and pressure of all standard fluids together.

Type:

callable(z)

rho_cb, rho_rel, p_rel

Cold matter alone; photons and neutrinos alone.

Type:

callable(z)

rho_std0, rho_rel0, Omega_cb

Their values today.

Type:

float

Omega_k
Type:

float

radiation

Whether photons and neutrinos are present at all.

Type:

bool

H0

Only for wrapped old-style models, whose E(z) may read it.

Type:

float

curvature(z)[source]

Omega_k (1+z)^2.

class cosmofit.theories.dark_sector.GrowthContext(ctx, E2, dlnH_dN)[source]

Bases: object

What a dark sector’s growth hooks may read: the standard fluids, the expansion, and its logarithmic slope.

Parameters:
ctx
Type:

ExpansionContext

E2
Type:

callable(z)

dlnH_dN

d ln H / d ln a.

Type:

callable(z)

cosmofit.theories.dark_sector.solve_linear(k, source, y0=1.0, n_min=-30.0, points=30001)[source]

Solve dy/dN = k y + s(N) from y(0) = y0 back to N = n_min, N = ln a, through its integrating factor:

y(N) = e^{kN} [ y0 + int_0^N e^{-kN’} s(N’) dN’ ]

Returns y as a function of z, interpolated in N – a cubic spline of ln |y| would assume a sign; the solution here is interpolated directly, on a grid fine enough that the cubic error is far below the 1e-9 the rest of the background works to.

Parameters:
Return type:

Callable

cosmofit.theories.dark_sector.N_MIN = -30.0

How far back (ln a) ODE-based sectors tabulate their solution: a = 1e-13, below everything the early-universe integrals reach.

Every dark sector by name.

In an input, background: {dark_energy: cpl} – or, for a sector with options of its own, dark_energy: {name: legacy, model: ...}. The old model class names ("CPL", "RunningVacuum", "FQExponential", …) are accepted too, case-insensitively.

cosmofit.theories.sectors.get_dark_sector(spec)[source]

A dark sector from a name, {"name": ..., **options}, an instance, or a DarkSector subclass.

Return type:

DarkSector

Dark energy on top of general relativity, as a component of the background.

A model here is only what makes it different from a cosmological constant: the density of its dark energy relative to today’s, f(z) = rho_de(z) / rho_de(0), and its equation of state w(z). Everything else – matter, radiation, massive neutrinos, curvature, the closure that fixes Omega_de – is the Background’s, written once instead of once per model.

The formulas are those of the original model classes, verbatim, and the tests check them against those classes.

class cosmofit.theories.dark_energy.DarkEnergy[source]

Bases: DarkSector

A dark-energy density history, added to the standard fluids:

E(z)^2 = rho_std(z) + Omega_k (1+z)^2 + Omega_de f(z), Omega_de = 1 - Omega_k - rho_std(0)

name and params (required, read by density() and w()) declare it.

density(z, **p)[source]

rho_de(z) / rho_de(0).

solve(ctx, **p)[source]

E(z)^2 as a function, for this context and these parameters, or None where the model has no solution.

dark_energy_today(ctx)[source]

Omega_de, the closure.

Return type:

float

w(z, **p)[source]

The equation of state.

cosmofit.theories.dark_energy.DARK_ENERGY = {'ba': <class 'cosmofit.theories.dark_energy.BA'>, 'cpl': <class 'cosmofit.theories.dark_energy.CPL'>, 'gcg': <class 'cosmofit.theories.dark_energy.GCG'>, 'gede': <class 'cosmofit.theories.dark_energy.GEDE'>, 'hu_sawicki': <class 'cosmofit.theories.dark_energy.HuSawicki'>, 'ide': <class 'cosmofit.theories.dark_energy.InteractingDarkEnergy'>, 'jbp': <class 'cosmofit.theories.dark_energy.JBP'>, 'lambda': <class 'cosmofit.theories.dark_energy.DarkEnergy'>, 'logarithmic': <class 'cosmofit.theories.dark_energy.Logarithmic'>, 'lscdm': <class 'cosmofit.theories.dark_energy.SignSwitchingLambda'>, 'pede': <class 'cosmofit.theories.dark_energy.PEDE'>, 'wcdm': <class 'cosmofit.theories.dark_energy.WCDM'>}

Every dark-energy model by name, with the old class names as aliases.

cosmofit.theories.dark_energy.get_dark_energy(name)[source]

A dark-energy model from its name (case-insensitive; "LCDM", "CPL" and the other old class names work), an instance, or a DarkEnergy subclass.

Return type:

DarkEnergy

Expansion from a modified Friedmann equation rather than a dark fluid.

Each of these maps the density of the standard fluids onto E^2 its own way. The old models wrote that map with Omega_m (1+z)^3 as the only density; here it is applied to all the standard fluids – the modification is to how gravity responds to energy density, and radiation is energy density. With radiation switched off every formula reduces to the old model’s, and the tests check that it does.

  • DGP (self-accelerating branch): E = sqrt(Omega_rc + rho) + sqrt(Omega_rc), curvature added outside.

  • Cardassian (modified polytropic): E^2 = rho [1 + (Omega_*^-q - 1) (rho/rho_0)^{q(n-1)}]^{1/q}.

  • f(Q) exponential, (E^2 - 2 lambda) e^{lambda/E^2} = rho, and f(T) power law, E^2 + c E^{2n} = rho: transcendental, solved by Newton’s method, flat only.

  • f(R,T) linear: the trace T = rho - 3p enters the source, so each fluid contributes rho + beta (3 rho - p) – dust with 1 + 3 beta, radiation (traceless) with 1 + (8/3) beta.

class cosmofit.theories.modified_gravity.DGP[source]

Bases: DarkSector

Dvali-Gabadadze-Porrati braneworld, self-accelerating branch.

solve(ctx)[source]

E(z)^2 as a function, for this context and these parameters, or None where the model has no solution.

mu(z, k, growth)[source]

mu = 1 + 1/(3 beta), beta = 1 - 2 H r_c [1 + Hdot/(3 H^2)], 2 H r_c = E / sqrt(Omega_rc).

class cosmofit.theories.modified_gravity.Cardassian[source]

Bases: DarkSector

Modified polytropic Cardassian expansion.

solve(ctx, n_card, q_card)[source]

E(z)^2 as a function, for this context and these parameters, or None where the model has no solution.

class cosmofit.theories.modified_gravity.FQExponential[source]

Bases: DarkSector

f(Q) = Q exp(lambda Q0/Q), with lambda fixed by E(0) = 1: lambda = 1/2 + W0(-rho_std(0) / (2 sqrt(e))).

mu(z, k, growth)[source]

mu = 1/f_Q, f_Q = e^{lambda/E^2} (1 - lambda/E^2).

newton_iterations = 30

Fixed Newton steps; the map is smooth and monotonic over the physical range, as in the old model.

solve(ctx)[source]

E(z)^2 as a function, for this context and these parameters, or None where the model has no solution.

class cosmofit.theories.modified_gravity.FTPowerLaw[source]

Bases: DarkSector

f(T) = T + alpha T^n_ft, with the amplitude fixed by E(0) = 1: E^2 + (rho_std(0) - 1) E^{2 n_ft} = rho_std. The root is checked, and NaN (no solution) returned where Newton’s method did not find one – for n_ft > 1/2 the equation stops having a real solution above some redshift.

mu(z, k, growth, n_ft)[source]

mu = 1/f_T = 1/(1 + n A E^{2n-2}), A = (rho_std(0) - 1)/(2n - 1); the n = 1/2 pole refused.

solve(ctx, n_ft)[source]

E(z)^2 as a function, for this context and these parameters, or None where the model has no solution.

class cosmofit.theories.modified_gravity.FRTLinear[source]

Bases: DarkSector

f(R,T) = R + 2 lambda T, beta = lambda / 8 pi:

E^2 = Omega_k (1+z)^2 + (1 + 3 beta) rho_std - beta p_std
  • (1 + 4 beta) Omega_L

with Omega_L from E(0) = 1.

mu(z, k, growth, beta)[source]

mu = 1 + 3 beta, the old model’s stated simplification.

solve(ctx, beta)[source]

E(z)^2 as a function, for this context and these parameters, or None where the model has no solution.

The holographic family, with radiation.

All three set rho_de = 3 M_p^2 / L^2 for some infrared length L and are flat only. The old models solved them in a matter-only universe; with photons and neutrinos present, each equation picks up the standard fluids’ pressure. Writing Omega = Omega_DE(z) and ' = d/d ln a, with E^2 = rho_std / (1 - Omega) in a flat universe:

HDE (future event horizon, rho = 3 c^2 / L^2):

Omega' = Omega (1 - Omega) [1 + 2 sqrt(Omega)/c + 3 p_std/rho_std]

ADE (conformal age, rho = 3 n^2 / eta^2):

Omega' = Omega (1 - Omega) [3 - 2 sqrt(Omega)/(n a) + 3 p_std/rho_std]

RDE (Ricci scalar, rho = 3 gamma (Hdot + 2 H^2)):

(gamma/2) (E^2)' + (2 gamma - 1) E^2 + rho_std = 0

Each is derived from rho_de and the continuity equation, with -2 H'/H = 3 (1 + w_total) carrying the standard fluids’ pressure; with only dust (p_std = 0) they are the old models’ equations exactly. Radiation’s 3p/rho = 1 changes the early-time behaviour: ADE’s dark energy tracks n^2 a^2 in the radiation era, not the n^2 a^2 / 4 of the matter era, and the transition between the two depends on when matter and radiation are equal – which is why ADE’s Omega_m, still fixed by n, is now found by iteration.

class cosmofit.theories.holographic.HDE[source]

Bases: DarkSector

Holographic dark energy, future-event-horizon cutoff, c_hde.

solve(ctx, c_hde)[source]

E(z)^2 as a function, for this context and these parameters, or None where the model has no solution.

class cosmofit.theories.holographic.ADE[source]

Bases: DarkSector

New agegraphic dark energy (conformal age), n_ade. Fixes the matter density from n_ade: the background does not take Omega_m with it.

matter_density(make_context, n_ade)[source]

For derives_matter sectors: today’s cold-matter density Omega_cb, given make_context(Omega_cb).

solve(ctx, n_ade)[source]

E(z)^2 as a function, for this context and these parameters, or None where the model has no solution.

class cosmofit.theories.holographic.RDE[source]

Bases: DarkSector

Ricci dark energy, gamma_rde.

solve(ctx, gamma_rde)[source]

E(z)^2 as a function, for this context and these parameters, or None where the model has no solution.

The running vacuum, Lambda(H) = c0 + 3 nu H^2, with radiation.

The vacuum exchanges energy with cold matter; photons and neutrinos are conserved. In units of today’s critical density, E^2 (1 - nu) = rho_cb + rho_rel + c + Omega_k a^-2, and the continuity equations combine into one linear equation for y = E^2:

y' = -3 (1 - nu) y + 3 c + Omega_k a^-2 - 3 p_rel,
c  = (1 - nu) - Omega_cb - rho_rel(0) - Omega_k,

with p_rel the photon and neutrino pressure and y(0) = 1. Without radiation this is the old model’s closed form – curvature term Omega_k (1+z)^2 / (1 - 3 nu) included – and with it, radiation enters with (1+z)^4 / (1 + 3 nu): the vacuum responds to radiation in H^2 as it does to everything else there. Massive neutrinos, whose pressure is not a fixed fraction of their density, are why this is integrated rather than written out.

class cosmofit.theories.running_vacuum.RunningVacuum[source]

Bases: DarkSector

Running vacuum model, nu.

solve(ctx, nu)[source]

E(z)^2 as a function, for this context and these parameters, or None where the model has no solution.

clustering_matter(z, growth, nu)[source]

rho_m = (1 - nu) E^2 - rho_rel - c - Omega_k a^-2.

matter_exchange(z, growth, nu)[source]

psi = [3 nu rho_m - nu (rho_rel' - 2 Omega_k a^-2)] / rho_m, rho_rel' = -3 (rho_rel + p_rel) – 3 nu when flat and radiation-free.

Any old-style model as a dark sector: models built from an action, with define_model, or by subclassing Cosmology.

The wrapped class supplies E(z) itself, without radiation – it never had any – so this works with radiation: false only. Its parameters beyond the background’s own (H0, Omega_m, Omega_k, …) become parameters of the background, defaulting to the class’s defaults:

theory:
  background:
    radiation: false
    dark_energy: {name: legacy, model: "mypackage.models:MyModel"}
class cosmofit.theories.legacy_expansion.LegacyExpansion(model='LCDM')[source]

Bases: DarkSector

Options

modelstr or type

A Cosmology subclass, a built-in model name, or an import path.

solve(ctx, **p)[source]

E(z)^2 as a function, for this context and these parameters, or None where the model has no solution.

matter_density(make_context, **p)[source]

For derives_matter sectors: today’s cold-matter density Omega_cb, given make_context(Omega_cb).

clustering_matter(z, growth, **p)[source]

Density of the matter that clusters, in units of today’s critical density. Cold matter by default: massive neutrinos free-stream on the scales growth data measure.

matter_exchange(z, growth, **p)[source]

psi = Q / (H rho_m), energy gained by clustering matter per Hubble time – None for conserved matter.

mu(z, k, growth, **p)[source]

G_eff / G_N at wavenumber k [h/Mpc] – None for general relativity.

jumps(**p)[source]

The wrapped model’s own – LsCDM’s sign switch, for one.

The early universe: the sound horizon at the drag epoch and at recombination, computed from the background’s own expansion.

The old sound-horizon calculator built its own H(a) from photons, neutrinos and omega_cb and assumed nothing else mattered before recombination; a model where something else did had its own E(z) patched in after the fact. Here the integral simply reads Background’s E(z), which already contains everything – an early dark energy, an extra matter-like component, a coupling – so there is nothing to patch.

Two quantities still come from fits to CAMB rather than from a recombination calculation: the drag and decoupling redshifts (z_drag_fit(), z_star_fit()). Both were calibrated in LCDM, where the densities reach them through the expansion rate they set; the drag fit is therefore evaluated at the cold-matter density that gives the background’s actual H(z_drag), which for a standard early universe is omega_cb itself.

Requires a background with radiation: true.

class cosmofit.theories.early.EarlyUniverse(info=None, name=None)[source]

Bases: Theory

Provides

rdrag and rstar [Mpc], zdrag, zstar, thetastar (100 r_s(z_*) / D_M(z_*)), and rs (z=..., the comoving sound horizon at any redshift).

Derived parameters

The same five, under CAMB’s names.

initialize()[source]

Set up from self.info. Override; called by __init__.

Return type:

None

get_requirements()[source]

What this component needs from theories: {quantity: options or None}.

Return type:

dict

check_model(model)[source]

Called last, with the assembled Model, for checks that need to see the whole of it – which datasets are combined, which parameters are sampled. Warn or raise here.

Return type:

None

get_can_provide()[source]

Quantities this theory can compute.

Return type:

list[str]

get_derived_params()[source]

Names of the derived parameters this component can output.

Return type:

list[str]

calculate(state, want_derived=True, **params)[source]

Compute everything requested at params into state. Return False if the parameters admit no solution (the point is then rejected, not an error).

Parameters:
get_rs(z)[source]

Comoving sound horizon at redshift z [Mpc].

Parameters:
  • info (dict | None)

  • name (str | None)

The linear growth of structure, on the native background.

The sub-horizon, quasi-static equation for the density contrast of the clustering matter, in N = ln a:

D’’ + (2 + dlnH/dN + psi) D’
  • [3/2 Omega_m(a) mu(a, k) - psi (2 + dlnH/dN) - psi’] D = 0

Omega_m(a) is the clustering matter’s share of H^2, mu the gravitational coupling a modified-gravity sector reports, psi the energy a coupled sector feeds the matter per Hubble time – each read from the dark sector’s hooks (DarkSector), 1 and 0 by default.

What is new against the old growth calculator is the background it sits on. That one had no radiation, so D proportional to a at a = 1e-4 was its growing mode. With radiation the growing mode at early times is Meszaros’s, D proportional to 1 + 3y/2, y = rho_m / rho_rel – the exact growing solution of this equation in a matter-plus-radiation universe – and that is where integration starts. Without radiation the old initial condition is kept, and the old results come back.

The clustering matter is the cold matter: massive neutrinos free-stream on the scales growth data measure (k = 0.1 h/Mpc is well above the free-streaming scale of a 0.06 eV neutrino). The old calculator counted them in, a ~0.5% difference in Omega_m(a) at that mass.

Where E(z) jumps, the equation is integrated in pieces and matched by continuity of H dD/dN, as in the old calculator.

class cosmofit.theories.growth.Growth(info=None, name=None)[source]

Bases: Theory

Options

kfloat

Wavenumber [h/Mpc] for a scale-dependent mu; default 0.1.

amplitude"sigma8" or "boltzmann"

Where today’s amplitude comes from: the parameter sigma8 (the default), or a Boltzmann code’s sigma8_0 – computed from the primordial amplitude, so a fit with CMB spectra does not carry a second amplitude nothing ties to the first.

param sigma8:

param with the default amplitude.:

param Provides:

param ——–:

param growth_factor (D:

param normalized to 1 today):

param growth_rate:

param (f = dlnD/dlna):

param sigma8_z and fsigma8 – each z=...:

param – and S8:

param with the default amplitude.:

param Derived parameters:

param ——————:

param S8 = sigma8 sqrt(Omega_m / 0.3):

param with the default amplitude:

param (with boltzmann:

param the Boltzmann code derives it).:

steps_per_efold = 32.57328990228013

Fixed RK4 steps per unit of ln a. The old calculator’s 300 steps over 9.2 e-folds, which it checked against an adaptive solver to 1e-8.

initialize()[source]

Set up from self.info. Override; called by __init__.

Return type:

None

accepts(name)[source]

Whether this component takes the input parameter name. Defaults to the names in params.

Parameters:

name (str)

Return type:

bool

get_default_params()[source]

Default declarations for parameters this component owns, overridden by the input’s params. params unless a component’s defaults depend on its options.

Return type:

dict

get_requirements()[source]

What this component needs from theories: {quantity: options or None}.

Return type:

dict

get_required_params()[source]

Input parameters this component cannot run without. Assembly fails, naming them, if the input does not provide them.

Return type:

list[str]

get_can_provide()[source]

Quantities this theory can compute.

Return type:

list[str]

get_derived_params()[source]

Names of the derived parameters this component can output.

Return type:

list[str]

check_model(model)[source]

Called last, with the assembled Model, for checks that need to see the whole of it – which datasets are combined, which parameters are sampled. Warn or raise here.

Return type:

None

calculate(state, want_derived=True, sigma8=None)[source]

Compute everything requested at params into state. Return False if the parameters admit no solution (the point is then rejected, not an error).

Parameters:
Parameters:
  • info (dict | None)

  • name (str | None)

CMB power spectra and sigma8 from CAMB, on the native background.

The old backend (CAMBBackend) translated an old-style model into CAMB’s parameters. This one reads them off the background theory: the densities it was solved with – omega_cb directly, so the neutrino density is never converted back from a mass with a separate constant – and the dark sector’s own w(z).

What CAMB can be given is decided by what a sector does, as before, now read off the sector’s hooks:

  • a dark-energy fluid on top of general relativity, with an equation of state w(z), is passed through CAMB’s PPF module as a table of w(a);

  • a sector that changes the gravitational coupling (mu), moves energy into matter (matter_exchange, clustering_matter) or makes E(z) jump is refused. CAMB would run for each of them – on a background it was not given, or with perturbations it does not have – and return a spectrum that looks reasonable and means nothing;

  • a modified Friedmann equation or a holographic sector has no w(z) to give it, and is refused too.

CAMB is optional (pip install "cosmofit[cmb]"); only a model with this theory in it imports it.

class cosmofit.theories.boltzmann.CAMB(info=None, name=None)[source]

Bases: Theory

Options

lmaxint

Highest multipole; likelihoods asking for more widen it. By default, the most any likelihood asks for – 30 for low-l EE alone – or 2508 if none says.

lens_potential_accuracyint

CAMB’s lensing accuracy; the largest any likelihood asks for is used. Default 1.

The primordial parameters ln1e10As, n_s and tau_reio default to Planck 2018’s best fit.

Provides

  • Cl – the lensed spectra from l = 0, keyed ell, tt, te, ee, bb and pp: C_l in muK^2, or D_l = l(l+1) C_l / 2 pi with ell_factor=True. pp is always [L(L+1)]^2 C_L / 2 pi, the convention Planck’s lensing likelihood is defined on.

  • sigma8_0 – sigma8 of the cold matter today, the amplitude the growth theory scales when its amplitude is boltzmann.

  • S8 – of all matter, as the derived parameter.

Derived parameters: sigma8 (all matter, as usually quoted), S8 = sigma8 sqrt(Omega_m/0.3) and A_s.

defaults = {'ln1e10As': 3.044, 'n_s': 0.9649, 'tau_reio': 0.0544}

Planck 2018 TT,TE,EE+lowE+lensing, as the old parameter defaults.

initialize()[source]

Set up from self.info. Override; called by __init__.

Return type:

None

accepts(name)[source]

Whether this component takes the input parameter name. Defaults to the names in params.

Parameters:

name (str)

Return type:

bool

get_default_params()[source]

Default declarations for parameters this component owns, overridden by the input’s params. params unless a component’s defaults depend on its options.

Return type:

dict

get_requirements()[source]

What this component needs from theories: {quantity: options or None}.

Return type:

dict

get_can_provide()[source]

Quantities this theory can compute.

Return type:

list[str]

get_derived_params()[source]

Names of the derived parameters this component can output.

Return type:

list[str]

initialize_with_provider(provider)[source]

Called once every component exists and requirements are resolved, with the provider this component reads through.

Return type:

None

check_model(model)[source]

Called last, with the assembled Model, for checks that need to see the whole of it – which datasets are combined, which parameters are sampled. Warn or raise here.

Return type:

None

calculate(state, want_derived=True, **params)[source]

Compute everything requested at params into state. Return False if the parameters admit no solution (the point is then rejected, not an error).

Parameters:
Parameters:
  • info (dict | None)

  • name (str | None)

cosmofit.theories.boltzmann.cmb_support(sector)[source]

Whether CAMB can compute spectra for a dark sector, and why not when it cannot – without importing CAMB.

Return type:

tuple[bool, str]

Native likelihoods

The datasets as likelihoods of the 2.0 core, reading the native theories.

Each likelihood here is one of the library’s datasets – the same data, the same covariance, the same chi2 – with its predictions read from the theories through the provider instead of from a model object it holds. The data loading and the statistics stay where they were: each wraps the dataset’s class and hands it a read-only view of the provider, ProviderCosmology, in place of a cosmology. Nothing in a likelihood can change a theory’s state.

What used to be a parameter of the cosmology because a likelihood read it there is now that likelihood’s own:

  • rd – a BAO likelihood reads the sound horizon from the early_universe theory by default (rd: computed), or takes it as a parameter with rd: free;

  • MB – a supernova likelihood that does not marginalize the absolute magnitude analytically takes it as a parameter;

  • tau_reio – read by the tau prior, shared with the CAMB theory when there is one;

  • A_planck – Planck’s absolute calibration, for the bandpower and low-l EE likelihoods (default 1; planck_lite carries its Gaussian prior).

The CMB spectra likelihoods read the camb theory’s Cl, each asking for the multipoles and lensing accuracy it needs.

Named in an input by family:

likelihood:
  bao.desi: {version: desi2025}
  sn.pantheonplus:
  cmb.distance_priors:
  external.bbn:

The old dataset names (desi, pantheon, …) still reach the old likelihoods through LegacyLikelihood, for the old models.

class cosmofit.likelihoods.native.ProviderCosmology(likelihood)[source]

Bases: object

The part of an old-style cosmology the datasets’ classes read, served from the provider and the likelihood’s own parameters. Read-only: there is nothing on it to set.

property recombination

The distance priors’ own recombination, CHW19’s conventions.

class cosmofit.likelihoods.native.DatasetLikelihood(info=None, name=None)[source]

Bases: Likelihood

One dataset of DATASET_REGISTRY, reading the native theories. Options other than this class’s own go to the dataset’s class (version, marginalize_MB, …).

Parameters:
  • info (dict | None)

  • name (str | None)

dataset: str = ''

Key of the dataset in DATASET_REGISTRY.

needs: tuple = ()

What the predictions are computed from.

uses_rd = False

Whether the predictions involve the BAO sound horizon.

initialize()[source]

Set up from self.info. Override; called by __init__.

Return type:

None

get_params()[source]

The parameters this likelihood takes, given its options.

Return type:

list[str]

accepts(name)[source]

Whether this component takes the input parameter name. Defaults to the names in params.

Parameters:

name (str)

Return type:

bool

get_default_params()[source]

Default declarations for parameters this component owns, overridden by the input’s params. params unless a component’s defaults depend on its options.

Return type:

dict

get_required_params()[source]

Input parameters this component cannot run without. Assembly fails, naming them, if the input does not provide them.

Return type:

list[str]

get_requirements()[source]

What this component needs from theories: {quantity: options or None}.

Return type:

dict

check_model(model)[source]

How the datasets are combined, once per model (from whichever is listed first): pairs that share a sample (data.metadata.conflicts()), and the two double counts that depend on options – Pantheon+’s Cepheids with a SH0ES H0, the full-posterior tau with plik_lite.

Return type:

None

logp(**params)[source]

ln L at the current point. params are this likelihood’s own input parameters (its nuisance parameters, say).

Return type:

float

cosmofit.likelihoods.native.NATIVE_LIKELIHOODS = {'bao.desi': <class 'cosmofit.likelihoods.native.DESI'>, 'bao.eboss_elg': <class 'cosmofit.likelihoods.native.EBOSSELG'>, 'bao.eboss_elg_fullshape': <class 'cosmofit.likelihoods.native.EBOSSELGFullShape'>, 'bao.eboss_lya': <class 'cosmofit.likelihoods.native.EBOSSLya'>, 'bao.lowz': <class 'cosmofit.likelihoods.native.BAOLowZ'>, 'bao.sdss': <class 'cosmofit.likelihoods.native.SDSSBAO'>, 'bao.sdss_fullshape': <class 'cosmofit.likelihoods.native.SDSSFullShape'>, 'cc.chronometers': <class 'cosmofit.likelihoods.native.CosmicChronometers'>, 'cmb.act_lensing': <class 'cosmofit.likelihoods.native.ACTLensing'>, 'cmb.distance_priors': <class 'cosmofit.likelihoods.native.DistancePriors'>, 'cmb.planck_lensing': <class 'cosmofit.likelihoods.native.PlanckLensing'>, 'cmb.planck_lite': <class 'cosmofit.likelihoods.native.PlanckLite'>, 'cmb.planck_lowe': <class 'cosmofit.likelihoods.native.PlanckLowE'>, 'external.bbn': <class 'cosmofit.likelihoods.native.BBN'>, 'external.h0': <class 'cosmofit.likelihoods.native.H0'>, 'external.tau': <class 'cosmofit.likelihoods.native.Tau'>, 'lss.s8': <class 'cosmofit.likelihoods.native.S8'>, 'rsd.fsigma8': <class 'cosmofit.likelihoods.native.FSigma8'>, 'sn.des_sn5yr': <class 'cosmofit.likelihoods.native.DESSN5YR'>, 'sn.pantheonplus': <class 'cosmofit.likelihoods.native.PantheonPlus'>, 'sn.union3': <class 'cosmofit.likelihoods.native.Union3'>}

Every native likelihood, by the name it is listed under.

What each dataset is: one place for its names, its family, its sources, and the samples it is built from.

Everything else that needs to know about a dataset reads it here: the legend labels figures print, the titles and groups the GUI shows, the native likelihood’s name, and – the part that matters for the science – which datasets must not be combined.

Which datasets must not be combined

That used to be a hand-written list of pairs, and the GUI kept its own copy, which had drifted to 7 of the 17 by the time anyone compared them. Here it follows from what each dataset is: every dataset lists the samples it measures – the same galaxies, the same patch of sky and redshift range, the same supernovae, the same CMB measurement in another form – and two datasets that share a sample are not independent. A new dataset declares its samples, and every pair it should not be combined with follows; no list to remember.

A sample counts only when combining the two would multiply a likelihood by part of itself. Neighbouring but independent data do not share one: the low-redshift BAO of 6dFGS and SDSS MGS lies below anything DESI or BOSS measured, and adds to either.

class cosmofit.data.metadata.DatasetInfo(likelihood, label, title, family, samples=frozenset({}), references=(), needs_camb=False)[source]

Bases: object

Parameters:
likelihood

Name of the native likelihood (likelihoods.native).

Type:

str

label

Short, for figure legends; several are joined to describe a fit.

Type:

str

title

Descriptive, for the GUI.

Type:

str

family

A key of FAMILIES.

Type:

str

samples

Keys of SAMPLES.

Type:

frozenset

references

arXiv identifiers of the measurement (see REFERENCES.md).

Type:

tuple

needs_camb

Whether its predictions run a Boltzmann code.

Type:

bool

cosmofit.data.metadata.conflicts(names)[source]

The pairs among names (dataset keys) that share a sample, each with why: {(first, second): reason}, in the order given.

Return type:

dict