Source code for cosmofit.core.run
"""
Running an input end to end.
"""
from __future__ import annotations
from .info import load_info, validate_info
from .model import Model
from .mpi import world
from .output import Output
from .registry import resolve
__all__ = ["run"]
[docs]
def run(info, seed: int | None = None, callback=None):
"""
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 :mod:`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
:class:`~core.post.Post` that ran instead.
"""
info = load_info(info)
if "post" in info:
from .post import Post
if world().size > 1:
raise RuntimeError("Post-processing runs in one process; run it without mpirun.")
post = Post(info)
post.run()
return info, post
info = validate_info(info)
if not info["sampler"]:
raise ValueError(
"run() needs a 'sampler' block (evaluate, minimize, ...). "
"To build the model alone, use get_model()."
)
model = Model(info)
(name, options), = info["sampler"].items()
sampler_cls = resolve("sampler", name, options)
if not getattr(sampler_cls, "parallel", False) and world().size > 1:
raise RuntimeError(
f"The {name!r} sampler runs in one process; under mpirun every "
f"process would run it into the same output. Run it without "
f"mpirun, or use mcmc."
)
options = {k: v for k, v in options.items() if k != "class"}
sampler = sampler_cls(options, model, seed=seed, output=Output(info))
sampler.callback = callback
sampler.run()
return info, sampler