Skip to main content

Bayesian mixture model population inference for gravitational wave observations

Project description

Vamana

Vamana is a Python package for Bayesian population inference of binary black hole (BBH) mergers using gravitational wave observations. It models the BBH population as a Gaussian mixture over component masses and aligned spins, with full correction for detector selection effects and merger rate estimation.

Methodology

The methodology is described in:

  • Tiwari, V. (2021). VAMANA: modeling binary black hole population with minimal assumptions. Classical and Quantum Gravity, 38(15), 155007. doi:10.1088/1361-6382/ac0b54
  • Tiwari, V. (2018). Estimation of the sensitive volume for gravitational-wave source populations using weighted Monte Carlo integration. Classical and Quantum Gravity, 35(14), 145009. doi:10.1088/1361-6382/aac89d

Scientific results obtained using Vamana are presented in:

  • Tiwari, V. & Fairhurst, S. (2021). The emergence of structure in the binary black hole mass distribution. ApJL, 913(2), L19. doi:10.3847/2041-8213/abfbe7
  • Tiwari, V. (2022). Exploring features in the binary black hole population. ApJ, 928(2), 155. doi:10.3847/1538-4357/ac589a
  • Tiwari, V. (2023). What's in a binary black hole's mass parameter? MNRAS, 527(1), 298. doi:10.1093/mnras/stad3155
  • Tiwari, V. (2025). Examining the gap in the chirp mass distribution of binary black holes. ApJ, 995, 177. doi:10.3847/1538-4357/ae2260
  • Tiwari, V. (2025). Population of binary black holes inferred from one hundred and fifty gravitational wave signals. arXiv:2510.25579.

Installation

pip install vamana

To use the nested sampler (dynesty):

pip install vamana[nested]

Overview

Vamana models the BBH population as a mixture of weighted Gaussians over primary mass, secondary mass, and aligned spin components. The number of mixture components, prior specification, and likelihood function are all user-configurable.

Key components

Data — loads and curates parameter estimation samples and injection campaigns across multiple observation runs.

Analysis — combines data, prior specification, builder, and likelihood into a single object for sampling.

run_mcmc_uniform_step — Metropolis-Hastings sampler with uniform CDF step proposals, adaptive step size, and joint proposals for correlated parameters.

run_dynesty — nested sampling via dynesty.

Prior files — plain-text prior specification files declaring parameter distributions, bounds, and proposal functions. Vamana ships with two ready-to-use prior files:

  • model_GWTC3.prior — prior configuration for GWTC-1 through GWTC-3
  • model_GWTC5.prior — prior configuration for GWTC-1 through GWTC-5

These are automatically found by name after pip install vamana. Users can also supply their own prior file by passing a full path.

Prior file format

# NAME    DEFINITION    DISTRIBUTION    Per_component    arg1    arg2    Proposal    pargs
weights   ...           dirichlet       True             0.0     1.0     dirichlet_joint
mu_m1     ...           m1_for_uniform_m1m2  True        6.0     75.0    mass_powerlaw_joint  -1.1
...
rate      ...           uniform_in_log  False            1.0     100.0

Parameters with no proposal function declared are moved using their distribution's CDF-step draw function in run_mcmc_uniform_step, or via adaptive Metropolis in run_mcmc.

Data loading

from vamana import Data
from vamana.curate import get_data_for_fitting

data = Data(curate_fn=get_data_for_fitting)

# GWTC-1 (O1+O2)
data.add(pattern='/path/to/pe/*o1o2*BBH*.hdf5', reader='read_pe_gwtc1',
         label='GWTC1', nsamp=2000)
data.add_injections('/path/to/injections/o1o2.hdf5',
                    reader='read_injections_gwtc1', label='GWTC1',
                    DETSNR_THR=3.0, NETSNR_THR=9.0)

# GWTC-2 (O3a)
data.add(pattern='/path/to/pe/*o3a*BBH*.hdf5', reader='read_pe_o3',
         label='GWTC2', nsamp=2000)
data.add_injections('/path/to/injections/o3a.hdf5',
                    reader='read_injections_o3', label='GWTC2', IFAR_thr=1.0)

# GWTC-3 (O3b)
data.add(pattern='/path/to/pe/*o3b*BBH*.hdf5', reader='read_pe_o3',
         label='GWTC3', nsamp=2000)
data.add_injections('/path/to/injections/o3b.hdf5',
                    reader='read_injections_o3', label='GWTC3', IFAR_thr=1.0)

data.check()
data.curate()

Running an analysis

from vamana.analysis import Analysis
from vamana.builders import mixture_builder
from vamana.likelihood import calculate_log_likelihood
from vamana.selection import get_vt
from vamana.samplers import run_mcmc_uniform_step

analysis = Analysis(
    'model_GWTC3.prior', data, ncomp=10,
    builder=mixture_builder,
    likelihood_fnc=calculate_log_likelihood,
    selection_fnc=get_vt
)

analysis.run(
    run_mcmc_uniform_step,
    nsteps=200000, nburn=100000, thin=1000,
    delta_u=0.015, chain_id=0,
    output='results/run'
)

This saves results/run_chain0.h5. For multiple chains, run the same script with different chain_id values — on a cluster via condor or slurm, pass the chain ID as a command-line argument:

import sys
chain_id = int(sys.argv[1]) if len(sys.argv) > 1 else 0
analysis.run(..., chain_id=chain_id, output='results/run')

Checking convergence and combining chains

Once all chains are complete, check convergence before combining:

from vamana.utils import convergence_report, combine_chains

# Gelman-Rubin R-hat and autocorrelation length across all chains
convergence_report('results/run_chain*.h5')

Output looks like:

==================================================
Convergence Report
==================================================
Chains:          8
Samples/chain:   100
Total samples:   800
==================================================

Gelman-Rubin R-hat:
  Max R-hat:     1.023
  Mean R-hat:    1.008
  Converged:     True
  Worst param:   kpop (R-hat=1.023)

Autocorrelation:
  Mean ACL:      12.3
  Max ACL:       28.1 (mu_m1_3)
  Min ESS:       284
  Suggested thin: 29
==================================================

If R-hat < 1.1 and ESS is sufficient, combine:

combine_chains('results/run_chain*.h5', output='results/combined.h5')

Loading posterior samples

from vamana.utils import load_samples

samples = load_samples('results/combined.h5')
samples['mu_m1'].shape   # (nsamples, ncomp)
samples['rate'].shape    # (nsamples,)

Requirements

  • Python >= 3.9
  • numpy >= 1.21
  • scipy >= 1.7
  • astropy >= 5.0
  • h5py >= 3.0
  • dynesty >= 2.0 (optional, for nested sampling)

Licence

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

vamana-2.0.0.tar.gz (45.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

vamana-2.0.0-py3-none-any.whl (48.0 kB view details)

Uploaded Python 3

File details

Details for the file vamana-2.0.0.tar.gz.

File metadata

  • Download URL: vamana-2.0.0.tar.gz
  • Upload date:
  • Size: 45.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.14

File hashes

Hashes for vamana-2.0.0.tar.gz
Algorithm Hash digest
SHA256 9926593ec86dd1c544612db52b55d98e1632b4bba032c473fd7ca70d1e9849ca
MD5 99c18b54ff501a61012fe23f8f56bbf3
BLAKE2b-256 6e066b3a92f26c886093bcd30a97c8551d17eb7fb7d1b36b16b7f9c37e11fa5d

See more details on using hashes here.

File details

Details for the file vamana-2.0.0-py3-none-any.whl.

File metadata

  • Download URL: vamana-2.0.0-py3-none-any.whl
  • Upload date:
  • Size: 48.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.14

File hashes

Hashes for vamana-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c62a7f4efcd38441ccbf15c490c1406b9a112c42985538aa2c40328e55f6dd9d
MD5 e2ba09b085684b9c0023d47040d02ce0
BLAKE2b-256 c37c51e42ddf1fa36c2931055d0223f89d8430a20ba014ca0f6c0ab9c8ef7b8e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page