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– theTheory/Likelihoodbase 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:
ppfThe inverse CDF, mapping the unit interval onto the parameter – the prior transform a nested sampler integrates through.
sampleDraws, for starting points and prior-predictive checks.
supportThe interval outside which the density is zero (possibly infinite), for optimizer bounds.
center,scaleA 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:
objectA normalized one-dimensional prior.
- as_dict()[source]¶
How an input writes this prior (
make_prior()reads it back).- Return type:
- class cosmofit.core.priors.Uniform(min, max)[source]¶
Bases:
PriorUniform on
[min, max].- as_dict()[source]¶
How an input writes this prior (
make_prior()reads it back).- Return type:
- class cosmofit.core.priors.Gaussian(loc, scale, min=-inf, max=inf)[source]¶
Bases:
PriorNormal with mean
locand standard deviationscale, optionally truncated to[min, max]and renormalized there.- as_dict()[source]¶
How an input writes this prior (
make_prior()reads it back).- Return type:
- class cosmofit.core.priors.LogUniform(min, max)[source]¶
Bases:
PriorUniform in
ln xon[min, max],0 < min < max– the prior that says “no preferred order of magnitude”.- as_dict()[source]¶
How an input writes this prior (
make_prior()reads it back).- Return type:
- cosmofit.core.priors.make_prior(spec)[source]¶
Build a
Priorfrom 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 optionalmin/maxtruncation{"dist": "loguniform", "min": a, "max": b}
- Raises:
ValueError – For anything else, naming what was not understood.
- Return type:
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 optionalref(where to start),proposal(a step scale) andlatexlabel.- 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 sampleomega_b(withdrop: True, so no component is handed it) and give the cosmology theOmega_bit 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:
objectOne parameter’s declaration. Build it with
parse_param().- Parameters:
- declaration()[source]¶
This parameter as an input’s
paramsblock 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.
- class cosmofit.core.parameters.ParameterSet(specs)[source]¶
Bases:
objectEvery parameter of a model, by role, and the operations a sampler needs on them.
- 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 insampledorder – as a{name: value}dict of the sampled parameters.- Return type:
- all_values(point)[source]¶
Sampled, fixed and dependent values together, dependents computed.
- Return type:
- to_input(point)[source]¶
The values components receive:
all_values()without the dropped parameters.- Return type:
- scales()[source]¶
A typical step per sampled parameter:
proposalif given, else therefwidth, else the prior’s.- Return type:
ndarray
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:
objectBase 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
paramsblock overrides them.
- 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 inparams.
- get_default_params()[source]¶
Default declarations for parameters this component owns, overridden by the input’s
params.paramsunless a component’s defaults depend on its options.- Return type:
- get_requirements()[source]¶
What this component needs from theories:
{quantity: options or None}.- Return type:
- class cosmofit.core.component.Theory(info=None, name=None)[source]¶
Bases:
ComponentA component that computes quantities for others.
Subclasses implement
get_can_provide(),calculate(), and eitherget_result()orget_<name>methods.- 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.
- n_calculations¶
Calls of
calculate(), as opposed to cache hits.
- 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
paramsintostate. ReturnFalseif the parameters admit no solution (the point is then rejected, not an error).
- compute(params, want_derived=True, upstream=())[source]¶
Make
current_statethe state atparams, from the cache if it holds one. ReturnsFalseifcalculate()rejected the point.upstreamidentifies the current states of the theories this one reads (theircurrent_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.
- class cosmofit.core.component.Likelihood(info=None, name=None)[source]¶
Bases:
ComponentA component that returns a log-likelihood.
Subclasses implement
logp(), reading theory results throughself.provider.
- class cosmofit.core.component.Provider(providers)[source]¶
Bases:
objectWhat 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.
- exception cosmofit.core.component.ComponentError[source]¶
Bases:
ValueErrorA 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. Asamplerblock, if any, is ignored here.
- affected_by(name)[source]¶
The components whose result changes when the sampled parameter
namedoes: those taking it, or a dependent parameter computed from it, and every component reading one of those.
- 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_paramsorder.
- logposterior(point, want_derived=True)[source]¶
Evaluate the model at
point(a dict, or an array insampled_paramsorder).A point outside the prior is not evaluated. A theory or likelihood that cannot produce a prediction there gives
-infwith the reason inrejected, counted inrejections.- Parameters:
want_derived (bool)
- Return type:
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/.ymlfile, or YAML text.- Return type:
- 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 (
Nonebecomes{}).- Raises:
ValueError – Naming the first thing that is wrong.
- Parameters:
info (dict)
- Return type:
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 incore.legacy;an import path,
package.module:Classorpackage.module.Class, for a component that lives in someone else’s package;an entry point in the group
cosmofit.theories,cosmofit.likelihoodsorcosmofit.samplers, so an installed package can register names of its own;the
classkey 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.
- cosmofit.core.registry.builtin_names(kind)[source]¶
Every name
resolveknows without an import path.
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
samplerblock – or apostblock, to reweight a finished run (seecore.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,Rminus1ortau,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 apostinput, thePostthat 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.yamlThe input as given.
chains/run.updated.yamlThe 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, thenminuslogpriorand each likelihood’schi2__<name>.chains/run.paramnames,chains/run.rangesFor getdist: each column’s name and LaTeX label (derived ones starred), and each sampled parameter’s prior support.
chains/run.covmatThe proposal covariance the sampler ended with, to start the next run from – or, from
fisher, the inverse Fisher matrix.chains/run.minimum.txtThe best fit
minimize(orfisher, before it expands) found, as one row of a chain.chains/run.profile.txtA profile likelihood: the fixed values,
chi2minimized over the rest, and where the rest went.chains/run.evidence.yamlNested 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
outputprefix,forceandresumedecide what happens here; withoutoutputnothing is written.
- 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
forcenorresumesays what to do with it, or ifresumefinds output written by a different input.- Return type:
- write_updated(model, sampler_options)[source]¶
The input as run, every default filled in.
- Parameters:
sampler_options (dict)
- Return type:
None
- exception cosmofit.core.output.OutputError[source]¶
Bases:
RuntimeErrorAn output prefix in a state the run cannot use.
- class cosmofit.core.output.ChainFile(path, columns)[source]¶
Bases:
objectOne chain on disk, appended to as it grows.
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:
SerialOne process, which is all of them; nothing is sent anywhere.
MPICommmpi4py’sCOMM_WORLD, for a run started undermpirun: every process runs the same input, andworld()hands each its place in it.PipeCommProcesses this one starts itself, with
spawn(), connected by pipes. Started with thespawnmethod – 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.MPIComm(comm)[source]¶
Bases:
objectmpi4py’sCOMM_WORLD.- Parameters:
comm (mpi4py.MPI.Comm)
- class cosmofit.core.mpi.PipeComm(rank, size, connections, processes=None)[source]¶
Bases:
objectProcesses connected by pipes to the first.
- Parameters:
- fail(error)[source]¶
From a process other than the first: report
errorand stop.- Parameters:
error (BaseException)
- Return type:
None
- cosmofit.core.mpi.world()[source]¶
The communicator this process runs in:
MPICommwhen started undermpirunwith more than one process andmpi4pyinstalled,Serialotherwise.
- cosmofit.core.mpi.spawn(size, target, args=())[source]¶
Start
size - 1processes, each callingtarget(comm, *args)with its ownPipeComm, and return the first process’s.targetandargsmust pickle: the new processes importtargetby name and rebuild everything else fromargs.
- exception cosmofit.core.mpi.WorkerError[source]¶
Bases:
RuntimeErrorA process of a parallel run failed; the message is its traceback.
- exception cosmofit.core.mpi.Aborted[source]¶
Bases:
RuntimeErrorRaised 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
- exception cosmofit.core.post.PostError[source]¶
Bases:
ValueErrorA 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:
TheoryA
Cosmologysubclass as a theory.Options¶
- modelstr or type
"LCDM","CPL", …, an import path, or the class.- compute_rdbool
Compute
rdfrom the densities, asFitter(compute_rd=True).rdis then not an input.- derive_sigma8bool
Take
sigma8from the Boltzmann code, asFitter(derive_sigma8=True).sigma8is then not an input.
Provides¶
cosmology(the live object the wrapped likelihoods read),E,H,DM,DH,DV,DA(eachz=...),rd,fsigma8(z=...).Derived parameters:
rd_computedandz_drag.- accepts(name)[source]¶
Whether this component takes the input parameter
name. Defaults to the names inparams.
- class cosmofit.core.legacy.LegacyLikelihood(info=None, name=None)[source]¶
Bases:
LikelihoodA dataset of
DATASET_REGISTRYas a likelihood:ln L = -chi2 / 2of 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, …).- get_requirements()[source]¶
What this component needs from theories:
{quantity: options or None}.- Return type:
- initialize_with_provider(provider)[source]¶
Called once every component exists and requirements are resolved, with the provider this component reads through.
- Return type:
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:
- 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:
objectThe core’s chains, wearing the part of
emcee.EnsembleSamplerthatFitterand 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,targetand 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.
- 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’smcmcoremceesampler, and make the result the fitter’s own:fitter.samplerbecomes aCoreChains, sosummary(),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.
- cosmofit.compat.profile_on_core(fitter, name, values)[source]¶
profile(), by the core’sprofilesampler:name,values,chi2,delta_chi2andparams(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.
- cosmofit.compat.fisher_on_core(fitter, point=None)[source]¶
fisher(), by the core’sfishersampler: atpoint, 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’sunstable_steps.
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.
Samplers¶
Samplers of the new core (see cosmofit.core).
evaluateThe model at one point: log-prior, every chi2, every derived value.
minimizeThe maximum of the posterior or the likelihood, in scaled coordinates, from one or more starts.
profileA profile likelihood: one parameter fixed at each of a list of values, the others minimized over.
fisherThe curvature at the best fit, with steps chosen by the likelihood, and its inverse as a Gaussian approximation to the posterior.
mcmcAdaptive Metropolis-Hastings, stopped by the Gelman-Rubin
R - 1, writing getdist-format chains.emceeemcee’s affine-invariant ensemble, stopped by the autocorrelation time.
nesteddynesty’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:
objectBase sampler.
- Parameters:
info (dict) – The sampler’s options from the input.
model (core.model.Model) – The model to sample.
seed (int, optional) – Seeds
rng. Aninfo["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 inrun(), and return what they found fromproducts().A sampler that cannot pick up where an earlier run stopped leaves
resumablefalse, and is refusedresume: true.- 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); seecore.run.run().
- class cosmofit.samplers.base.ChainColumns(model)[source]¶
Bases:
objectThe columns of a chain row after
weightandminuslogpost: the sampled parameters, the derived ones not dropped,minuslogprior, and each likelihood’schi2__<name>(dots as underscores).- Parameters:
model (core.model.Model)
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:
SamplerOptions¶
- overridedict, optional
Values for sampled parameters. The rest are taken at their
ref(or, failing that, their prior’s center).
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:
SamplerOptions¶
- methodstr
Any
scipy.optimize.minimizemethod; default"L-BFGS-B"."Nelder-Mead"and"Powell"need no gradient.- startsint
Independent starting points: the first at the
refcenters, the rest drawn fromref(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.
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:
SamplerOptions¶
- 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 - 1is below this. Default 0.01.- learn_proposalbool
Learn the proposal covariance from the chains. Default True.
- learn_proposal_Rminus1_maxfloat
Learn only once
R - 1is 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 (
# namesheader, 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.
- 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.
- products(skip=0.0)[source]¶
samples(sampled parameters),weightsandminuslogpostof every chain together, each chain’s rows underchains, thecolumnsof those rows, the finalRminus1, whether itconverged, theacceptancerate, the proposalcovmat, and theprogressof every check.skipdrops that fraction of each chain’s weight from its start – the burn-in, as getdist’signore_rowsdoes. The files keep every sample.
- cosmofit.samplers.mcmc.gelman_rubin(chains)[source]¶
Multivariate
R - 1of weighted chains[(x, w), ...]: the largest eigenvalue ofW^-1 B, withWthe mean covariance within chains andBthe covariance of their means.
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:
MinimizeOptions¶
- paramstr
The sampled parameter to profile.
- valueslist or dict
Values to hold it at: a list, or
{min, max, n}fornevenly 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.
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:
SamplerOptions¶
- pointdict, optional
Where to expand, every sampled parameter by name. Without it the best fit is found first, by
minimizewith the options underminimize.- minimizedict, optional
Options for that minimization (
method,starts, …).- ignore_priorbool
Expand
-2 ln Lrather 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,refwidth or prior width).- check_stepbool
Recompute the diagonal at half the steps and warn if it moves. Default True;
2 dmore evaluations.
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:
SamplerOptions¶
- walkersint, optional
Default
max(32, 4 d); at least2 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
tauchanged 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
refallowed per walker for a finite start.- max_timefloat or None
Seconds before stopping, converged or not.
- 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.
- products(skip=None)[source]¶
samples(sampled parameters) andweightsof every walker together, the same rows underchains(one chain), theircolumns, the autocorrelation timetau, whether itconverged, the meanacceptanceand theprogressof every check.skipdrops that fraction of the steps from the start; by default2 tausteps, the burn-in emcee’s authors recommend.
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:
SamplerOptions¶
- 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.
- products()[source]¶
log_evidenceandlog_evidence_error; theinformation(prior-to-posterior KL divergence, nats) and the Bayesian modeldimensionality2 Var[ln L](Handley & Lemos 2019); the weightedsamples, theirweights(largest 1) and the same as rows underchainswith theircolumns;nliveandn_evaluations.- Return type:
Native theories¶
Native theories of the 2.0 core.
backgroundBackground– the expansion history, radiation and massive neutrinos included, with any dark sector fromDARK_SECTORS.early_universeEarlyUniverse– the sound horizon at the drag epoch and at recombination, from the background’s own expansion.growthGrowth– the linear growth factor, growth rate andf sigma8, on the background’s expansion and through the dark sector’s growth hooks.cambCAMB– CMB spectra andsigma8from 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", … – seeDARK_ENERGY.- parameterization{“fractional”, “physical”}
"fractional"(default):H0,Omega_m,Omega_b, withOmega_mcounting 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.Falsedrops photons and neutrinos and treatsOmega_mas pure(1+z)^3matter: 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:
TheoryThe background expansion; see the module docstring.
Provides¶
E,H[km/s/Mpc],comoving_distance,DM,DH,DV,DA[Mpc] (eachz=...),wandOmega_de_z(z=...), andbackground_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].- get_default_params()[source]¶
Default declarations for parameters this component owns, overridden by the input’s
params.paramsunless a component’s defaults depend on its options.- Return type:
- accepts(name)[source]¶
Whether this component takes the input parameter
name. Defaults to the names inparams.
- get_required_params()[source]¶
Input parameters this component cannot run without. Assembly fails, naming them, if the input does not provide them.
- 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
paramsintostate. ReturnFalseif the parameters admit no solution (the point is then rejected, not an error).
- 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 isget_Omega_de_z().
- get_Omega_de_z(z)[source]¶
Everything in
E^2beyond 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.
- 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 forH = 100 km/s/Mpc, as it entersH(a)^2.One massive species carries the whole of
m_nuwhen it is positive; the remainingN_eff - 3.044/3effective species are massless.
- 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 equationp = -rho - (1/3) d rho / d ln a– a third of the density while relativistic, falling to zero as the massive species slows down.
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^2some 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:
objectA 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 forOmega_k = 0only;radiation_ok, has a form with radiation (Falsefor a wrapped model that only ever hadE(z)without it); andderives_matter, fixes the cold-matter density itself, so the background does not takeOmega_m(oromega_cdm).- solve(ctx, **p)[source]¶
E(z)^2as a function, for this context and these parameters, orNonewhere the model has no solution.- Parameters:
ctx (ExpansionContext)
- Return type:
Callable | None
- matter_density(make_context, **p)[source]¶
For
derives_mattersectors: today’s cold-matter densityOmega_cb, givenmake_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.
- Parameters:
growth (GrowthContext)
- matter_exchange(z, growth, **p)[source]¶
psi = Q / (H rho_m), energy gained by clustering matter per Hubble time –Nonefor conserved matter.- Parameters:
growth (GrowthContext)
- mu(z, k, growth, **p)[source]¶
G_eff / G_Nat wavenumberk[h/Mpc] –Nonefor general relativity.- Parameters:
k (float)
growth (GrowthContext)
- 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:
objectThe 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:
- class cosmofit.theories.dark_sector.GrowthContext(ctx, E2, dlnH_dN)[source]¶
Bases:
objectWhat a dark sector’s growth hooks may read: the standard fluids, the expansion, and its logarithmic slope.
- Parameters:
ctx (ExpansionContext)
E2 (Callable)
dlnH_dN (Callable)
- ctx¶
- Type:
- 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)fromy(0) = y0back toN = n_min,N = ln a, through its integrating factor:y(N) = e^{kN} [ y0 + int_0^N e^{-kN’} s(N’) dN’ ]
Returns
yas a function ofz, interpolated inN– a cubic spline ofln |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.
- 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 aDarkSectorsubclass.- Return type:
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:
DarkSectorA 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)
nameandparams(required, read bydensity()andw()) declare it.
- 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 aDarkEnergysubclass.- Return type:
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 - 3penters the source, so each fluid contributesrho + beta (3 rho - p)– dust with1 + 3 beta, radiation (traceless) with1 + (8/3) beta.
- class cosmofit.theories.modified_gravity.DGP[source]¶
Bases:
DarkSectorDvali-Gabadadze-Porrati braneworld, self-accelerating branch.
- class cosmofit.theories.modified_gravity.Cardassian[source]¶
Bases:
DarkSectorModified polytropic Cardassian expansion.
- class cosmofit.theories.modified_gravity.FQExponential[source]¶
Bases:
DarkSectorf(Q) = Q exp(lambda Q0/Q), with lambda fixed by
E(0) = 1:lambda = 1/2 + W0(-rho_std(0) / (2 sqrt(e))).- newton_iterations = 30¶
Fixed Newton steps; the map is smooth and monotonic over the physical range, as in the old model.
- class cosmofit.theories.modified_gravity.FTPowerLaw[source]¶
Bases:
DarkSectorf(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 – forn_ft > 1/2the equation stops having a real solution above some redshift.
- class cosmofit.theories.modified_gravity.FRTLinear[source]¶
Bases:
DarkSectorf(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_LfromE(0) = 1.
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:
DarkSectorHolographic dark energy, future-event-horizon cutoff,
c_hde.
- class cosmofit.theories.holographic.ADE[source]¶
Bases:
DarkSectorNew agegraphic dark energy (conformal age),
n_ade. Fixes the matter density fromn_ade: the background does not takeOmega_mwith it.
- class cosmofit.theories.holographic.RDE[source]¶
Bases:
DarkSectorRicci dark energy,
gamma_rde.
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:
DarkSectorRunning vacuum model,
nu.
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:
DarkSectorOptions¶
- modelstr or type
A
Cosmologysubclass, a built-in model name, or an import path.
- solve(ctx, **p)[source]¶
E(z)^2as a function, for this context and these parameters, orNonewhere the model has no solution.
- matter_density(make_context, **p)[source]¶
For
derives_mattersectors: today’s cold-matter densityOmega_cb, givenmake_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.
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:
TheoryProvides¶
rdragandrstar[Mpc],zdrag,zstar,thetastar(100 r_s(z_*) / D_M(z_*)), andrs(z=..., the comoving sound horizon at any redshift).Derived parameters¶
The same five, under CAMB’s names.
- get_requirements()[source]¶
What this component needs from theories:
{quantity: options or None}.- Return type:
- 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
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:
TheoryOptions¶
- 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’ssigma8_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_zandfsigma8– eachz=...: - 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.
- accepts(name)[source]¶
Whether this component takes the input parameter
name. Defaults to the names inparams.
- get_default_params()[source]¶
Default declarations for parameters this component owns, overridden by the input’s
params.paramsunless a component’s defaults depend on its options.- Return type:
- get_requirements()[source]¶
What this component needs from theories:
{quantity: options or None}.- Return type:
- get_required_params()[source]¶
Input parameters this component cannot run without. Assembly fails, naming them, if the input does not provide them.
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 ofw(a);a sector that changes the gravitational coupling (
mu), moves energy into matter (matter_exchange,clustering_matter) or makesE(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:
TheoryOptions¶
- 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_sandtau_reiodefault to Planck 2018’s best fit.Provides¶
Cl– the lensed spectra froml = 0, keyedell,tt,te,ee,bbandpp:C_lin muK^2, orD_l = l(l+1) C_l / 2 piwithell_factor=True.ppis always[L(L+1)]^2 C_L / 2 pi, the convention Planck’s lensing likelihood is defined on.sigma8_0–sigma8of the cold matter today, the amplitude the growth theory scales when itsamplitudeisboltzmann.S8– of all matter, as the derived parameter.
Derived parameters:
sigma8(all matter, as usually quoted),S8 = sigma8 sqrt(Omega_m/0.3)andA_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.
- accepts(name)[source]¶
Whether this component takes the input parameter
name. Defaults to the names inparams.
- get_default_params()[source]¶
Default declarations for parameters this component owns, overridden by the input’s
params.paramsunless a component’s defaults depend on its options.- Return type:
- get_requirements()[source]¶
What this component needs from theories:
{quantity: options or None}.- Return type:
- initialize_with_provider(provider)[source]¶
Called once every component exists and requirements are resolved, with the provider this component reads through.
- Return type:
None
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 theearly_universetheory by default (rd: computed), or takes it as a parameter withrd: 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_litecarries 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:
objectThe 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:
LikelihoodOne dataset of
DATASET_REGISTRY, reading the native theories. Options other than this class’s own go to the dataset’s class (version,marginalize_MB, …).- uses_rd = False¶
Whether the predictions involve the BAO sound horizon.
- accepts(name)[source]¶
Whether this component takes the input parameter
name. Defaults to the names inparams.
- get_default_params()[source]¶
Default declarations for parameters this component owns, overridden by the input’s
params.paramsunless a component’s defaults depend on its options.- Return type:
- get_required_params()[source]¶
Input parameters this component cannot run without. Assembly fails, naming them, if the input does not provide them.
- get_requirements()[source]¶
What this component needs from theories:
{quantity: options or None}.- Return type:
- 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 SH0ESH0, the full-posteriortauwithplik_lite.- Return type:
None
- 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.