Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
106 commits
Select commit Hold shift + click to select a range
45be840
add parsing single character booleans
PabloCorcho May 14, 2026
b1e01fb
remove leading arrow in logger and include a feature-weight generic m…
PabloCorcho May 14, 2026
27bac1e
homogenize default flux and luminosity units
PabloCorcho May 14, 2026
357e94f
change transparency
PabloCorcho May 15, 2026
b878ff4
remove comments
PabloCorcho May 15, 2026
c72e94c
remove unused import and implement table format parser
PabloCorcho May 15, 2026
06e95bc
add default units and correct lsf for redshift
PabloCorcho May 18, 2026
163a546
add docs, normalise chi2, save z likelihood
PabloCorcho May 18, 2026
b127849
add temporary spec-z post-processing function
PabloCorcho May 18, 2026
62fc7e5
update docs
PabloCorcho May 18, 2026
7eb811f
enforce numba
PabloCorcho May 18, 2026
7c1a884
update docs
PabloCorcho May 18, 2026
bef5ecb
remove unused methods and update docs
PabloCorcho May 18, 2026
32ef20d
remove unused methods and update docs
PabloCorcho May 18, 2026
0098802
bugfix
PabloCorcho May 18, 2026
50cfabc
bugfix
PabloCorcho May 18, 2026
632f06f
update docs
PabloCorcho May 18, 2026
37998ba
add comments
PabloCorcho May 18, 2026
c31f095
add missing dependency
PabloCorcho May 13, 2026
9cefcf3
add missing dependency
PabloCorcho May 13, 2026
6bb8dc8
refactor io function
PabloCorcho May 22, 2026
5b6ef7e
add guards and bugfixes
PabloCorcho May 22, 2026
9746485
handle pipeline concatenations
PabloCorcho May 22, 2026
1fa5424
add samplers
PabloCorcho May 22, 2026
021bdaf
replace astropy models by custom class to speed up performance and im…
PabloCorcho May 22, 2026
e695976
add size and percentiles
PabloCorcho May 22, 2026
491bf88
allow users to choose losvd kernel model
PabloCorcho May 22, 2026
f56c1f8
update tests
PabloCorcho May 23, 2026
7fd1ba0
bugfix
PabloCorcho May 23, 2026
4604e12
account for transforms
PabloCorcho May 25, 2026
cd02727
autocorrelation times
PabloCorcho May 25, 2026
341b93c
update docs
PabloCorcho May 30, 2026
d7ecc09
add batch
PabloCorcho May 30, 2026
2f9e9ff
add new batch class for parallel launching
PabloCorcho May 30, 2026
3627796
update reqs
PabloCorcho May 30, 2026
77de612
add batch testing
PabloCorcho May 30, 2026
722cc9a
update readme
PabloCorcho May 30, 2026
ef78911
add parsing single character booleans
PabloCorcho May 14, 2026
fdc9b03
remove leading arrow in logger and include a feature-weight generic m…
PabloCorcho May 14, 2026
1852968
homogenize default flux and luminosity units
PabloCorcho May 14, 2026
b733e08
change transparency
PabloCorcho May 15, 2026
8dcaaba
remove comments
PabloCorcho May 15, 2026
3ee18f8
remove unused import and implement table format parser
PabloCorcho May 15, 2026
872c8b2
add default units and correct lsf for redshift
PabloCorcho May 18, 2026
b1ea082
add docs, normalise chi2, save z likelihood
PabloCorcho May 18, 2026
9c9a5e5
add temporary spec-z post-processing function
PabloCorcho May 18, 2026
0b80818
update docs
PabloCorcho May 18, 2026
b8fad15
enforce numba
PabloCorcho May 18, 2026
4595868
update docs
PabloCorcho May 18, 2026
1a77e0a
remove unused methods and update docs
PabloCorcho May 18, 2026
7ee498c
remove unused methods and update docs
PabloCorcho May 18, 2026
34dd322
bugfix
PabloCorcho May 18, 2026
d229beb
bugfix
PabloCorcho May 18, 2026
ecdb6c5
update docs
PabloCorcho May 18, 2026
0fab635
add comments
PabloCorcho May 18, 2026
40c3a46
refactor io function
PabloCorcho May 22, 2026
7bd2a47
add guards and bugfixes
PabloCorcho May 22, 2026
31406ec
handle pipeline concatenations
PabloCorcho May 22, 2026
6f3955a
add samplers
PabloCorcho May 22, 2026
564fcc0
replace astropy models by custom class to speed up performance and im…
PabloCorcho May 22, 2026
a8683d1
add size and percentiles
PabloCorcho May 22, 2026
23ef357
allow users to choose losvd kernel model
PabloCorcho May 22, 2026
a0fe570
update tests
PabloCorcho May 23, 2026
2a0fe5f
bugfix
PabloCorcho May 23, 2026
8c8947e
account for transforms
PabloCorcho May 25, 2026
c350d5c
autocorrelation times
PabloCorcho May 25, 2026
d641176
remove stale code
PabloCorcho May 26, 2026
ed87c95
bugfixes
PabloCorcho May 26, 2026
a624c6d
move table operations to io module
PabloCorcho May 27, 2026
1a41d7f
check for negative values and raise warnings
PabloCorcho May 27, 2026
8036cb1
move table operations to io
PabloCorcho May 27, 2026
451ebee
add line kinematics in physical units and expand documentation
PabloCorcho May 27, 2026
ca5b207
reconcile branches
PabloCorcho Jun 1, 2026
ad65508
reconcile branches
PabloCorcho Jun 1, 2026
86b9f03
update test
PabloCorcho Jun 1, 2026
a273a1b
remove numpy constraints
PabloCorcho Jun 1, 2026
ed4a1e7
run all tests
PabloCorcho Jun 1, 2026
72bec8a
use inverse variance during spectra likelihood for speeding up
PabloCorcho Jun 1, 2026
8bf5fca
update persitance methods to avoid numpy compat issues
PabloCorcho Jun 1, 2026
7957a5b
add custom sampler
PabloCorcho Jun 1, 2026
6732192
add custom sampler
PabloCorcho Jun 1, 2026
e339d78
refactor likelihood methods
PabloCorcho Jun 1, 2026
85ce81e
allow for different options
PabloCorcho Jun 1, 2026
ce22713
test different methods
PabloCorcho Jun 1, 2026
1f64c1a
add dependencies
PabloCorcho Jun 1, 2026
136cb16
add tests for new likelihood module
PabloCorcho Jun 1, 2026
5246108
normalise likelihoods
PabloCorcho Jun 1, 2026
824dc20
do not use it for testing
PabloCorcho Jun 5, 2026
c0aeace
handle request error
PabloCorcho Jun 5, 2026
e453141
bugfix
PabloCorcho Jun 5, 2026
aa96b8f
renormiles by effective number of pixels
PabloCorcho Jun 5, 2026
5f68720
homogenise parameter naming convention
PabloCorcho Jun 5, 2026
bf2e70f
renormiles by effective number of pixels
PabloCorcho Jun 5, 2026
57bbd93
fix lsf redshift
PabloCorcho Jun 5, 2026
40e4d7d
update tutorials
PabloCorcho Jun 5, 2026
d9345ea
store edges instead of bins
PabloCorcho Jun 11, 2026
6ef6e93
update notebooks
PabloCorcho Jun 11, 2026
b1158cd
remove stales imports
PabloCorcho Jun 13, 2026
a40124f
add test feature masking
PabloCorcho Jun 13, 2026
efb3b3c
allow for feature-based weights
PabloCorcho Jun 13, 2026
ba79288
write ini values file when use_transforms=True
PabloCorcho Jun 13, 2026
3435e26
re-organise methods
PabloCorcho Jun 15, 2026
2d68d53
Merge branch 'develop' into update-dev
PabloCorcho Jun 15, 2026
bb4c3e6
rename test
PabloCorcho Jun 15, 2026
75f39f5
bugfix
PabloCorcho Jun 15, 2026
13993e4
Merge pull request #48 from PabloCorcho/update-dev
PabloCorcho Jun 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,4 @@ jobs:
pip install .
- name: Test with pytest
run: |
pytest tests/test_sfh.py tests/test_pipeline_module.py tests/test_run.py
# make test-units
# make test-notebooks
pytest tests/test_*
127 changes: 106 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,126 @@
[![Documentation Status](https://readthedocs.org/projects/besta/badge/?version=latest)](https://besta.readthedocs.io/en/latest/?badge=latest)
[![test](https://github.com/PabloCorcho/besta/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/PabloCorcho/besta/actions/workflows/test.yml)

BESTA is a Python package for inferring stellar population properties from spectroscopic and/or photometric data using Bayesian inference and Monte Carlo methods.
BESTA is a Python library for Bayesian inference of galaxy stellar population properties from spectroscopic and/or photometric observations.

Full documentation is available at [besta.readthedocs.io](https://besta.readthedocs.io).
It provides a practical interface to build fitting workflows on top of:

## Framework
- [Population Synthesis Toolkit (PST)](https://github.com/paranoya/population-synthesis-toolkit) for stellar population modeling.
- [CosmoSIS](https://cosmosis.readthedocs.io) for parameter estimation and sampling.

BESTA is built on top of two core libraries:
Full user and API documentation: [besta.readthedocs.io](https://besta.readthedocs.io)

- **[Population Synthesis Toolkit (PST)](https://github.com/paranoya/population-synthesis-toolkit)** — flexible stellar population synthesis models.
- **[CosmoSIS](https://cosmosis.readthedocs.io)** — modular parameter estimation via Monte Carlo sampling.
## What BESTA Can Do

## Features
BESTA supports end-to-end stellar population fitting workflows, including:

### Pipeline modules
- Spectroscopic and photometric inference workflows.
- Joint fitting of stellar population and kinematics.
- Configurable star formation history (SFH) parameterizations.
- Grid-based and emulator-based SFH inference options.
- Sequential and batch execution of fitting pipelines.
- Post-processing and visualization utilities for fitted solutions.

Ready-to-use CosmoSIS pipeline modules are provided in `besta.pipeline_modules`:
For detailed pipeline setup, module-level configuration, and examples, see the online documentation:

| Module | Description |
|---|---|
| `GalaxySpectraModule` | Full spectroscopic SED fitting |
| `FullSpectralFitModule` | Joint stellar population and kinematics fit from spectra |
| `GalaxyPhotometryModule` | Broadband photometric SED fitting |
| `SFHPhotometryGridModule` | SFH inference from photometry via model grid |
| `SFHPhotometryEmulatorModule` | SFH inference from photometry via emulator |
- [Quick guide](https://besta.readthedocs.io/en/latest/quick_guide.html)
- [Configuration reference](https://besta.readthedocs.io/en/latest/configuration.html)
- [Pipeline manager docs](https://besta.readthedocs.io/en/latest/manager.html)
- [Tutorials](https://besta.readthedocs.io/en/latest/index.html)

### Star formation history models
## Installation

Analytic: `ExponentialSFH`, `DelayedTauSFH`, `DelayedTauQuenchedSFH`, `LogNormalSFH`, `LogNormalQuenchedSFH`
### Python version

Piece-wise: `FixedTimeSFH`, `FixedTime_sSFR_SFH`, `FixedMassFracSFH`
- `Python >= 3.10`

## Installation
### Install from PyPI

```bash
pip install besta
```

Requires Python ≥ 3.10. See the [installation guide](https://besta.readthedocs.io) for CosmoSIS setup instructions.
### Install from source

Depending on your platform and scientific Python installation, you may also need system libraries typically used by MPI and linear algebra backends (for example OpenMPI, BLAS/LAPACK, and a Fortran compiler).

```bash
git clone https://github.com/PabloCorcho/besta.git
cd besta
python -m pip install -r requirements.txt
python -m pip install .
```

### Ubuntu/Debian example:

```bash
sudo apt update
sudo apt install -y \
gfortran \
liblapack-dev \
libopenblas-dev \
openmpi-bin \
openmpi-common \
libopenmpi-dev \
libgtk2.0-dev
```

using conda

```bash
conda install -c conda-forge \
gcc_linux-64 \
gxx_linux-64 \
gfortran_linux-64 \
openmpi \
mpi4py \
gsl \
cfitsio \
fftw \
lapack \
openblas \
git \
make \
cmake \
pkg-config
```

Package names can vary by distribution and version. If your environment already provides BLAS/LAPACK and MPI through conda, you may not need to install all system-level packages.

## Contributing

Contributions are welcome, including bug fixes, new features, tests, docs, and tutorials.

### Report issues

- Open issues or feature requests at: [github.com/PabloCorcho/besta/issues](https://github.com/PabloCorcho/besta/issues)

### Contribute code

1. Fork the repository.
2. Create a feature branch.
3. Implement your changes and add or update tests.
4. Update documentation when behavior or APIs change.
5. Open a pull request with a clear summary and motivation.

### Development quick start

```bash
git clone https://github.com/PabloCorcho/besta.git
cd besta
python -m pip install -r requirements.txt
python -m pip install -e .
pytest -q
```

## Citation

If BESTA contributes to your research, please cite the project and acknowledge the software in your publication.

## License

BSD 3-Clause.

## Contact

For questions, please send an email to p.corcho.caballero@rug.nl
2 changes: 1 addition & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ sphinx>=5.0.0
nbsphinx>=0.9.3
cosmosis
astropy>=5.0.0
numpy<2.0
numpy
matplotlib>=3.7.0
extinction>=0.4
scipy>=1.10
Expand Down
15 changes: 15 additions & 0 deletions docs/source/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,9 @@ Photometry-only fit
[runtime]
sampler = maxlike

[maxlike]
method = Powell

[output]
filename = ./photometry_fit
format = text
Expand Down Expand Up @@ -297,6 +300,13 @@ Single-spectrum fit
[runtime]
sampler = maxlike emcee

[maxlike]
method = Powell

[emcee]
nwalkers = 16
nsteps = 500

[output]
filename = ./spectral_fit
format = text
Expand Down Expand Up @@ -334,6 +344,11 @@ spectra of the same galaxy simultaneously with shared parameters:
from besta.pipeline_modules.full_spectral_fit import FullSpectralFitModule

cfg = {

"runtime": {"sampler": "maxlike emcee"},
"maxlike": {"method": "Nelder-Mead", "tolerance": 1e-3, "maxiter": 3000},
"emcee": {"walkers": 32, "samples": 100, "nsteps": 100},

"output": {"filename": "./fit_all", "format": "text"},
"pipeline": {
"modules": "FullSpectralFit_blue FullSpectralFit_red",
Expand Down
118 changes: 54 additions & 64 deletions docs/source/grid.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,52 @@ Grid-Based Inference
====================

BESTA includes a direct **model-grid inference** workflow that does not require
CosmoSIS samplers. This mode is useful when you already have a finite model
library and want fast posterior evaluation over that library.

Why use the grid module instead of CosmoSIS sampling?
-----------------------------------------------------

Use the grid module when:

- Your model space is already discretized (for example: precomputed SED/SSP libraries).
- You want robust, repeatable inference with no MCMC tuning.
- You need high throughput over many objects using candidate selection and parallel workers.
- You want direct control over priors/likelihoods in Python.

Prefer the CosmoSIS pipeline (see :ref:`pipeline_manager`) when:

- Your parameter space is continuous and not naturally represented by a fixed grid.
- You need sampler diagnostics and chain-level convergence checks.
- You rely on existing module wiring in the CosmoSIS runtime.

CosmoSIS samplers. This mode is particularly useful when you already have a finite model
library and want fast posterior evaluation over that library or the volume of data very large.

Core Concepts
-------------

The model-grid workflow is built around several key modules/classes:

- :class:`besta.grid.grid.ModelGrid`: container for model observables/targets and metadata.
- :class:`besta.grid.grid.GridFitter`: computes posterior weights over grid models.
- :mod:`besta.grid.prob`: prior and likelihood building blocks.
- :mod:`besta.grid.binning`: candidate selectors to avoid evaluating the full grid for every object.

Working with ModelGrids
-----------------------

A :class:`~besta.grid.grid.ModelGrid` is a container of a grid of models split into ``observables`` and ``targets`` (see example below). They support multiple I/O formats:

- FITS tables: :meth:`~besta.grid.grid.ModelGrid.from_fits_table`,
``ModelGrid.to_fits_table(...)``
- HDF5: :meth:`~besta.grid.grid.ModelGrid.from_hdf5`,
:meth:`~besta.grid.grid.ModelGrid.to_hdf5`
- Pickle: :meth:`~besta.grid.grid.ModelGrid.from_pickle`,
:meth:`~besta.grid.grid.ModelGrid.to_pickle`
- automatic loader: :meth:`~besta.grid.grid.ModelGrid.load_auto`

Priors and Likelihoods
----------------------

The grid module is fully Bayesian; you choose the ingredients from
:mod:`besta.grid.prob`:

- priors: :class:`~besta.grid.prob.FlatPrior`, :class:`~besta.grid.prob.CompositePrior`,
:class:`~besta.grid.prob.ObservableDependentPrior`, and others,
- likelihoods: :class:`~besta.grid.prob.GaussianProductLikelihood`,
:class:`~besta.grid.prob.CompositeLikelihood`, etc.

This gives a similar statistical structure to sampling methods, but evaluated
directly on a finite model set instead of drawing chains.


Minimal Workflow
----------------

1. Build or load a :class:`~besta.grid.grid.ModelGrid`.
2. Create a :class:`~besta.grid.grid.GridFitter` with a likelihood and prior.
2. Create a :class:`~besta.grid.grid.GridFitter` with a likelihood and a set of priors.
3. Evaluate posterior summaries for one object, or run :meth:`~besta.grid.grid.GridFitter.fit_batch` for many.

Example (single-object posterior on one target):
Expand All @@ -48,12 +60,12 @@ Example (single-object posterior on one target):
from besta.grid import ModelGrid, GridFitter
from besta.grid.prob import GaussianProductLikelihood, FlatPrior

# N models, P observables, Q targets
# N models, 3 observables, 4 targets
grid = ModelGrid(
observables=obs_models, # shape (N, P)
targets=target_models, # shape (N, Q)
observables=obs_models, # shape (N, 3)
targets=target_models, # shape (N, 3)
observable_names=["mag_g", "mag_r", "mag_i"],
target_names=["logM", "age", "Z", "z"],
target_names=["logM", "age", "Z", "z"], # (stellar mass, mean age, metals, redshift)
)

fitter = GridFitter(
Expand All @@ -63,43 +75,45 @@ Example (single-object posterior on one target):
use_standardised=True,
)

x = np.array([22.1, 21.5, 21.2]) # observed data (P,)
sx = np.array([0.03, 0.03, 0.04]) # observational errors (P,)
x = np.array([22.1, 21.5, 21.2]) # observed data (3,)
sigma_x = np.array([0.03, 0.03, 0.04]) # observational errors (3,)
bins = np.linspace(7.0, 12.0, 101) # bins for logM

# Estimate the marginal stellar mass posterior PDF
post_logM, centers = fitter.posterior_over_target(
x_native=x,
sigma_native=sx,
target_col="logM",
sigma_native=sigma_x,
target_col="logM",
bins=bins,
)


Batch Inference (many objects)
------------------------------
Batch Inference
----------------

For catalogs, use :meth:`~besta.grid.grid.GridFitter.fit_batch`.
It supports:
For large samples, use :meth:`~besta.grid.grid.GridFitter.fit_batch`.
This method supports:

- optional candidate selection (`binner=`),
- thread/process parallelism (`n_jobs`, `backend`),
- posterior truncation controls (`posterior_keep_mass`, etc.),
- optional per-target summary statistics (`stats_for`, `stats_bins`),
- optional HDF5 output (`output_hdf5_path`).


.. code-block:: python

from besta.grid.binning import KDTreeBinner

binner = KDTreeBinner(dims=[0, 1, 2]).fit(grid) # select candidates in observable space
binner = KDTreeBinner(dims=[0, 1, 2]).fit(grid) # Use the first three observable columns

results = fitter.fit_batch(
X_native=X_catalog, # shape (M, P)
SIG_native=SIG_catalog, # shape (M, P)
binner=binner,
n_jobs=8,
backend="thread",
stats_for=["logM", "age"],
stats_for=["logM", "age"], # the posterior statistics for these two quantities
stats_bins=[np.linspace(7, 12, 120), np.linspace(0, 14, 120)],
output_hdf5_path="grid_fit_results.h5",
output_hdf5_group="/run1",
Expand All @@ -111,39 +125,15 @@ It supports:
pass


Priors and Likelihoods
----------------------
Candidate selection
^^^^^^^^^^^^^^^^^^^

The grid module is fully Bayesian; you choose the ingredients from
:mod:`besta.grid.prob`:
This is an essential feature when it comes to using large high-dimensional model grids and large datasets. The binners act as model cadidate selectors, rather than using the entire grid on each evaluation, based on the observables of the input sources. This reduces significantly the number of posterior evaluations (sometimes by orders of magnitude).

- priors: :class:`~besta.grid.prob.FlatPrior`, :class:`~besta.grid.prob.CompositePrior`,
:class:`~besta.grid.prob.ObservableDependentPrior`, and others,
- likelihoods: :class:`~besta.grid.prob.GaussianProductLikelihood`,
:class:`~besta.grid.prob.CompositeLikelihood`, etc.
Posterior analysis
^^^^^^^^^^^^^^^^^^

This gives a similar statistical structure to sampling methods, but evaluated
directly on a finite model set instead of drawing chains.


Input/Output and Reproducibility
--------------------------------

:class:`~besta.grid.grid.ModelGrid` supports multiple formats:

- FITS tables: :meth:`~besta.grid.grid.ModelGrid.from_fits_table`,
``ModelGrid.to_fits_table(...)``
- HDF5: :meth:`~besta.grid.grid.ModelGrid.from_hdf5`,
:meth:`~besta.grid.grid.ModelGrid.to_hdf5`
- Pickle: :meth:`~besta.grid.grid.ModelGrid.from_pickle`,
:meth:`~besta.grid.grid.ModelGrid.to_pickle`
- automatic loader: :meth:`~besta.grid.grid.ModelGrid.load_auto`
BESTA includes some built-in tools for post-processing the posterior PDF and estimate several key quantities such as percentiles, MAP, or covariance matrix, per source.


Practical Tips
--------------

- Start with `FlatPrior + GaussianProductLikelihood` as a baseline.
- If the grid is large, use a binner to cut candidate counts before posterior evaluation.
- Use `return_mode="iter"` for low-memory streaming over large catalogs.
- Write batch outputs to HDF5 for reproducible downstream post-processing.
Loading
Loading