Skip to content

Repository files navigation

BayeSED3: A code for Bayesian SED synthesis and analysis of galaxies and AGNs

BayeSED3 Logo
"With four parameters I can fit an elephant, and with five I can make him wiggle his trunk."
- Attributed to John von Neumann

BayeSED3 is a general and sophisticated tool for the full Bayesian interpretation of spectral energy distributions (SEDs) of galaxies and AGNs. It performs Bayesian parameter estimation using posterior probability distributions (PDFs) and Bayesian SED model comparison using Bayesian evidence. BayeSED3 supports various built-in SED models and can emulate other SED models using machine learning techniques.

Key Features

  • Explore the BayeSED3-AI Assistant 🚀 or Ask DeepWiki for interactive help and guidance!
  • Multi-component SED synthesis and analysis of galaxies and AGNs
  • Flexible stellar population synthesis modeling
  • Flexible dust attenuation and emission modeling
  • Flexible stellar and gas kinematics modeling
  • Non-parametric and parametric star formation history options
  • Comprehensive AGN component modeling (Accretion disk, BLR, NLR, Torus)
  • Intergalactic medium (IGM) absorption modeling
  • Handling of both photometric and spectroscopic data
  • Bayesian parameter estimation and model comparison
  • Machine learning techniques for SED model emulation
  • Parallel processing support for improved performance
  • User-friendly CLI, Python script and GUI interfaces

Installation

Platforms: Linux x86_64 · macOS (x86_64 and ARM64) · Windows via WSL (Linux binaries)

OpenMPI 4.1.6

Required. pip does not install it. BayeSED3 looks for conda, system, or a local build; if none is found it will try to compile OpenMPI 4.1.6 itself.

conda install -c conda-forge openmpi=4.1.6

Or a system package: Ubuntu/Debian sudo apt-get install openmpi-bin openmpi-common libopenmpi-dev · Fedora sudo dnf install openmpi openmpi-devel · macOS brew install openmpi.

Compile from source (optional):

wget https://download.open-mpi.org/release/open-mpi/v4.1/openmpi-4.1.6.tar.gz
tar xzvf openmpi-4.1.6.tar.gz
cd openmpi-4.1.6
./configure --prefix=$PWD/../openmpi
make
make install

pip

pip install -U git+https://github.com/hanyk/BayeSED3.git           # latest (main)
#pip install -U git+https://github.com/hanyk/BayeSED3.git@v2026.08.23  # release

git clone https://github.com/hanyk/BayeSED3.git && cd BayeSED3                                    # latest (main)
# wget -O BayeSED3-2026.08.23.zip https://github.com/hanyk/BayeSED3/archive/refs/tags/v2026.08.23.zip && unzip BayeSED3-2026.08.23.zip && cd BayeSED3-2026.08.23
pip install -e .                                                   # editable
pip install -U .                                                   # non-editable
pip install -e '.[gui]'                                            # GUI

bayesed3                                                           # CLI
pip uninstall bayesed3

Optional components

HDF5 utilities (optional):

  • Ubuntu/Debian: sudo apt-get install h5utils
  • Fedora: sudo dnf install hdf5-tools
  • macOS (with Homebrew): brew install h5utils

tkinter (required for GUI):

  • Ubuntu/Debian: sudo apt-get install python3-tk
  • Fedora: sudo dnf install python3-tkinter
  • macOS (with Homebrew): brew install python-tk

Usage examples

Run from the repository root.

  1. SDSS spectroscopic SED analysis
    python tests/run_test.py gal plot --Ntest 1
    python tests/run_test.py qso plot --Ntest 1
    

Best-fit gal Best-fit qso

  1. photometric SED analysis
    python tests/run_test.py test1 plot
    python tests/run_test.py test2 plot
    

Best-fit mock_phot Best-fit W0533

  1. mock CSST photometric and/or spectroscopic SED analysis
    python tests/run_test.py test3 phot plot
    python tests/run_test.py test3 spec plot
    python tests/run_test.py test3 both plot
    

Best-fit csst_mock_phot Best-fit csst_mock_spec Best-fit csst_mock_both pdftree csst_mock_all

  1. A new approach to constraining properties of AGN host galaxies by combining image and SED decomposition

jupyter-notebook observation/agn_host_decomp/demo.ipynb

Python Interface

Quick Start Examples:

from bayesed import BayeSEDParams, SEDInference, BayeSEDInterface, BayeSEDResults

params = BayeSEDParams.galaxy(
    input_file='observation/test/gal.txt',
    outdir='tests/output_quick_start',
    ssp_model='bc2003_hr_stelib_chab_neb_2000r',
    sfh_type='exponential',
    dal_law='calzetti',
    save_sample_par=True,  # needed for posterior plots
)

inference = SEDInference()
inference.priors_init(params)
# Optional: inference.set_prior('log(age/yr)', min_val=8.5, max_val=9.8, confirm=False)
results = inference.run(params, Ntest=2)  # Results: posteriors, evidence, plots
# execution = BayeSEDInterface(Ntest=2).run(params)  # Execution: stdout, parameter list, returncode
# results = BayeSEDResults(params.outdir, catalog_name='gal')

results.print_summary()

# Access parameters and objects
free_params = results.get_free_parameters()
available_objects = results.list_objects()

# Load all parameters as astropy Table from HDF5 file
hdf5_table = results.load_hdf5_results()
# Built-in SNR filtering
high_snr_table = results.load_hdf5_results(filter_snr=True, min_snr=5.0)

# Access all statistical estimates for specific parameters
age_table = results.get_parameter_values('log(age/yr)[0,1]')
mass_table = results.get_parameter_values('log(Mstar)[0,1]')

custom_labels = {
    # Free parameters
    'log(age/yr)[0,1]': r'\log(age/\mathrm{yr})',
    'log(tau/yr)[0,1]': r'\log(\tau/\mathrm{yr})',
    'log(Z/Zsun)[0,1]': r'\log(Z/Z_\odot)',
    'Av_2[0,1]': r'A_V',
    # Derived parameters
    'log(Mstar)[0,1]': r'\log(M_\star/M_\odot)',
    'log(SFR_{100Myr}/[M_{sun}/yr])[0,1]': r'\log(\mathrm{SFR}/M_\odot\,\mathrm{yr}^{-1})'
}

results.set_parameter_labels(custom_labels)
results.plot_bestfit()
results.plot_posterior_free()
results.plot_posterior_derived(max_params=5)
results.plot_posterior(params=['log(age/yr)[0,1]', 'log(Z/Zsun)[0,1]', 'log(Mstar)[0,1]', 'log(SFR_{100Myr}/[M_{sun}/yr])[0,1]'])  # Mixed free+derived parameters

# Object-level analysis
if available_objects:
    object_id = available_objects[0]
    object_results = BayeSEDResults('tests/output_quick_start', object_id=object_id, catalog_name='gal')
    object_results.plot_bestfit()

    object_results.set_parameter_labels(custom_labels)
    object_results.plot_posterior_free()
    object_results.plot_posterior_derived(max_params=5)
    object_results.plot_posterior(params=['log(age/yr)[0,1]', 'log(Z/Zsun)[0,1]', 'log(Mstar)[0,1]', 'log(SFR_{100Myr}/[M_{sun}/yr])[0,1]'])  # Mixed free+derived parameters

AGN Fitting:

from bayesed import BayeSEDParams, SEDInference

params = BayeSEDParams.agn(
    input_file='observation/test/qso.txt',
    outdir='tests/output_agn_fitting',
    ssp_model='bc2003_hr_stelib_chab_neb_2000r',
    sfh_type='exponential',
    dal_law='calzetti',
    agn_components=['dsk', 'blr', 'nlr', 'feii'],  # Disk, BLR, NLR, FeII
    save_sample_par=True,
)

inference = SEDInference()
inference.priors_init(params)
results = inference.run(params, Ntest=2)  # first 2 objects; drop Ntest for a full catalog
results.print_summary()

Advanced Features

Prior Management

BayeSED3 provides a powerful API for managing parameter priors programmatically without manually editing .iprior files.

Basic Usage:

from bayesed import SEDInference, BayeSEDParams

# Initialize and load priors
params = BayeSEDParams.galaxy(input_file='observation/test/gal.txt', outdir='tests/output_prior_management')
inference = SEDInference()
inference.priors_init(params)

# View and modify priors (confirm=False for scripts; default True prompts on stdin)
inference.print_priors()
inference.set_prior('log(age/yr)', min_val=8.5, max_val=9.8, nbin=60, confirm=False)

# List all available prior types
inference.list_prior_types()  # Uniform, Gaussian, Gamma, Beta, StudentT, Weibull, …

# Use different prior types (Uniform, Gaussian, Gamma, Beta, StudentT, …)
inference.set_prior('log(age/yr)', prior_type='Gaussian',
                   min_val=8.0, max_val=12.0, hyperparameters=[10.0, 1.0],
                   confirm=False)

# Regex / substring matches (also pass confirm=False in scripts)
inference.set_prior('^Av_.*', prior_type='Gaussian', hyperparameters=[1.0, 0.3],
                   confirm=False)
inference.set_prior('age', min_val=8.0, max_val=10.0, confirm=False)  # matches log(age/yr), …

# Query without modifying
inference.set_prior('age')  # Shows all parameters containing 'age'

# Reset to auto-generated defaults (flag on set_prior, not a separate method)
inference.set_prior('log(age/yr)', reset_to_default=True, confirm=False)
inference.set_prior('Av_.*', reset_to_default=True, confirm=False)  # all Av parameters

Working with Data Arrays

import numpy as np
import os
from bayesed import BayeSEDInterface, BayeSEDParams, SEDInference
from bayesed.data import SEDObservation

# Create observations from arrays (synthetic data for demonstration)
obs = SEDObservation(
    ids=['galaxy_001', 'galaxy_002'],
    z_min=[0.1, 0.2],
    z_max=[0.15, 0.25],
    phot_filters=['SLOAN/SDSS.g', 'SLOAN/SDSS.r', 'SLOAN/SDSS.i'],
    phot_fluxes=np.array([[12.5, 25.1, 18.3], [15.2, 28.9, 22.1]]),
    phot_errors=np.array([[1.2, 2.5, 1.8], [1.5, 2.9, 2.2]]),
    input_type=0  # Flux in μJy
)

# Convert to BayeSED input format
os.makedirs('observation/demo_analysis', exist_ok=True)
input_file = obs.to_bayesed_input('observation/demo_analysis', 'demo_catalog')

# Download filters from SVO
bayesed = BayeSEDInterface()
filter_files = bayesed.prepare_filters_from_svo(
    svo_filter_ids=['SLOAN/SDSS.g', 'SLOAN/SDSS.r', 'SLOAN/SDSS.i'],
    output_dir='observation/demo_analysis/filters'
)

# Create and run analysis
params = BayeSEDParams.galaxy(
    input_file=input_file,
    outdir='tests/output_data_arrays',
    filters=filter_files['filters_file'],
    filters_selected=filter_files['filters_selected_file'],
    save_sample_par=True,
)
inference = SEDInference()
inference.priors_init(params)
results = inference.run(params)

Custom Model Configuration

from bayesed import BayeSEDParams, SEDInference
from bayesed.model import SEDModel

# Create galaxy instance with dust emission (using real data from observation/test2/)
galaxy = SEDModel.create_galaxy(
    ssp_model='bc2003_lr_BaSeL_chab',
    sfh_type='exponential',
    dal_law='smc'
)
galaxy.add_dust_emission()  # Add dust emission component

# Create AGN instance with torus
agn = SEDModel.create_agn(agn_components=['tor'])

# Assemble configuration using real data files
params = BayeSEDParams(
    input_type=0,  # Flux in μJy
    input_file='observation/test2/test.txt',
    outdir='tests/output_custom_model',
    filters='observation/test2/filters.txt',
    filters_selected='observation/test2/filters_selected.txt',
    save_sample_par=True  # Enable posterior sample generation
)
params.add_galaxy(galaxy)
params.add_agn(agn)

inference = SEDInference()
inference.priors_init(params)
results = inference.run(params)

Multi-Model Comparison

from bayesed import BayeSEDParams, SEDInference
from bayesed.results import standardize_parameter_names, plot_posterior_comparison

# Same input data, different models
input_file = 'observation/test/gal.txt'

def run_config(outdir, sfh_type, dal_law):
    params = BayeSEDParams.galaxy(
        input_file=input_file,
        outdir=outdir,
        ssp_model='bc2003_hr_stelib_chab_neb_2000r',
        sfh_type=sfh_type,
        dal_law=dal_law,
        save_sample_par=True,
    )
    inference = SEDInference()
    inference.priors_init(params)
    return inference.run(params)  # Results

results1 = run_config('tests/output_model1_exp_calzetti', 'exponential', 'calzetti')
results2 = run_config('tests/output_model2_delayed_smc', 'delayed', 'smc')

# Standardize parameter names across models for comparison
results_list = [results1, results2]
standardize_parameter_names(results_list)

# Create comparison plots showing how model choice affects parameter inference
plot_posterior_comparison(
    results_list,
    labels=['Exp+Calzetti', 'Delayed+SMC'],
    output_file='model_comparison.png'
)

# Compare Bayesian evidence (prefer log_evidence; raw INSlogZ is only present when INS wrote it)
evidence1 = results1.get_evidence()
evidence2 = results2.get_evidence()
delta_logZ = evidence1['log_evidence'] - evidence2['log_evidence']
delta_logZ_err = (evidence1['log_evidence_error']**2 + evidence2['log_evidence_error']**2)**0.5

Advanced Analytics

Compute parameter correlations, statistics, and integrate with GetDist for advanced posterior analysis:

from bayesed import BayeSEDResults

# Load results with intelligent configuration detection
# Note: If multiple catalogs exist, specify catalog_name explicitly
results = BayeSEDResults('tests/output_quick_start', catalog_name='gal')

# Get available parameter names (with component IDs like [0,1])
free_params = results.get_free_parameters()
derived_params = results.get_derived_parameters()
# Example: ['z', 'log(age/yr)[0,1]', 'log(tau/yr)[0,1]', 'log(Z/Zsun)[0,1]', 'Av_2[0,1]', ...]

# Load HDF5 data with SNR filtering
hdf5_table = results.load_hdf5_results(filter_snr=True, min_snr=3.0)

# Compute parameter correlations (use actual parameter names with component IDs)
correlations = results.compute_parameter_correlations(['log(age/yr)[0,1]', 'log(Z/Zsun)[0,1]', 'Av_2[0,1]'])

# Get parameter statistics
stats = results.get_parameter_statistics(['log(age/yr)[0,1]', 'log(Z/Zsun)[0,1]', 'Av_2[0,1]'])

# Object-level analysis
objects = results.list_objects()
object_id = objects[0]  # e.g., 'spec-0285-51930-0184_GALAXY_STARFORMING'

# GetDist integration with intelligent caching for custom posterior analysis
samples = results.get_getdist_samples(object_id=object_id)
samples.label = 'Galaxy Model'

# Use GetDist for advanced visualization and analysis
from getdist import plots
import matplotlib.pyplot as plt

g = plots.get_subplot_plotter()
g.triangle_plot([samples], ['log(age/yr)[0,1]', 'log(Z/Zsun)[0,1]', 'Av_2[0,1]'], filled=True)
plt.show()

For more detailed documentation and advanced usage, see docs/BayeSED3.md.

Graphical User Interface (GUI)

bayesed3-gui

From a clone without install: python bayesed_gui.py.

BayeSED3 GUI

File Descriptions

License

This project is licensed under the MIT License. See the LICENSE file for details.

Contributions

Issues and pull requests are welcome. Please make sure to update tests before submitting a pull request.

Citation

The further development of BayeSED needs your support. If BayeSED has been of benefit to you, either directly or indirectly, please consider citing our papers:

More Information

For more information about MultiNest, please refer to the README_multinest.txt file.

Star History

Star History Chart

About

A Bayesian SED synthesis and analysis tool for galaxies and AGNs, featuring an interface optimized for both humans and AI agents.

Topics

Resources

Stars

20 stars

Watchers

2 watching

Forks

Releases

Used by

Contributors

Languages