Skip to main content

Binary black hole population phenomenology: remnants, recoil kicks, retention, and hierarchical mergers

Project description

gwGenealogy

arXiv arXiv arXiv arXiv License: MIT

gwGenealogy

A Python toolkit for binary black-hole (BBH) phenomenology: sampling BBH populations, computing remnant properties, modeling hierarchical mergers with simple back-of-the-envelope calculations in dense stellar clusters, and analyzing remnant retention across astrophysical environments. For more detailed studies of hierarchical mergers in clusters, we recommend using rapster or other dedicated packages.

This package is a culmination of my works into understanding hierarchical mergers with my amazing collaborators Digvijay Wadekar and Konstantinos Kritos.

Comments/suggestions/criticisms are always welcome!

Package structure

gwGenealogy/
├── utils/      — Distribution samplers, coordinate transforms, conversions, statistics
├── binaries/   — BBH population sampling (masses, spins, redshifts, GWTC models), BBHRemnant
├── stellar/    — Stellar evolution (Fryer12, SEVN), Kroupa IMF, natal kicks
├── hosts/      — Plummer clusters, star cluster sampling, escape velocities, environment retention
├── core/       — Hierarchical mergers, BH seed growth, IMBH formation probability, retention grids

Installation

git clone https://github.com/tousifislam/gwGenealogy.git
cd gwGenealogy
pip install -e .

Dependencies

  • numpy, scipy, matplotlib, h5py
  • gwModels >= 0.1.6 — remnant mass, spin, and kick models (required; 0.1.6 adds the batched flow.sample/log_prob the kick code relies on)
  • surfinBH — NR surrogate remnant models (optional)

Quick start

Sample a BBH population and compute remnants

import numpy as np
from gwGenealogy.binaries import BBHs, BBHRemnant, sample_masses, sample_spins

m1, m2 = sample_masses(5000, m_min=5, m_max=50, m1_distribution='powerlaw', alpha=-2.35, seed=42)
chi1, chi2 = sample_spins(5000, chi_max=1.0, spin_magnitude='beta', spin_angles='isotropic', seed=43)

# sample_spins returns Cartesian spin vectors; BBHs takes magnitudes + angles
bbh = BBHs(m1=m1, m2=m2,
           a1=np.linalg.norm(chi1, axis=1), a2=np.linalg.norm(chi2, axis=1),
           theta1=np.arccos(chi1[:, 2] / np.linalg.norm(chi1, axis=1)),
           theta2=np.arccos(chi2[:, 2] / np.linalg.norm(chi2, axis=1)),
           phi1=np.arctan2(chi1[:, 1], chi1[:, 0]) % (2 * np.pi),
           phi2=np.arctan2(chi2[:, 1], chi2[:, 0]) % (2 * np.pi))
rem = BBHRemnant(bbh=bbh, precessing=True)
# rem.Mf, rem.af, rem.vkick

Hierarchical mergers across generations

from gwGenealogy.core import HierarchicalMergersInClusterPopulation

sim = HierarchicalMergersInClusterPopulation(n_samples=50000, chi_max=0.2, m_min=3, m_max=60,
                                              kick_model='gwmodel', seed=42)
data = sim.simulate(verbose=True)
fig, axes = sim.plot_generations(data)

BH seed growth and IMBH formation

from gwGenealogy.core import MonteCarloBHSeedGrowth

mc = MonteCarloBHSeedGrowth(v_esc=300, Z=0.005, chi_max=0.2, m_seed=10.0,
                             m_targets=[250], kick_model='gwmodel', seed=42)
result = mc.simulate(n_experiments=10000, verbose=True)

Retention probability grids

from gwGenealogy.core import BBHRetentionProbabilityOverChiq
import numpy as np

grid = BBHRetentionProbabilityOverChiq(
    q_values=np.linspace(1, 10, 50),
    chi_max_values=np.linspace(0.01, 1, 50),
    v_esc_values=[50, 100, 200, 500],
    kick_models=['hlz', 'gwmodel'], seed=42)
grid.compute(verbose=True)
fig, axes = grid.plot_heatmap_all_vesc()

GWTC population sampling

The GWTC population files are large (hundreds of MB) and are not bundled with the package; fetch them once from Google Drive (requires pip install gdown):

from gwGenealogy.binaries import download_gwtc_data, sample_gwtc_population, available_catalogs

download_gwtc_data()              # one-time: into ~/.gwGenealogy/data (or $GWGENEALOGY_DATA)

available_catalogs()
pop = sample_gwtc_population(50000, catalog='gwtc5', source='posterior', seed=42)
# pop['mass_1'], pop['a1'], pop['chi_eff'], pop['redshift'], ...

Environment retention

from gwGenealogy.hosts import compute_multi_environment_retention, ENVIRONMENTS

ret = compute_multi_environment_retention(v_kick_array)
# ret['GC'], ret['NSC'], ret['EG'], ret['DG'], ret['MW'], ret['M31']

Tutorials

# Notebook Description
01 Distributions Core distribution samplers and JSD
02 Stellar evolution Kroupa IMF, Fryer12/SEVN remnants, natal kicks
03 BBH nonprecessing BBHs + BBHRemnant with nonprecessing models
04 BBH precessing BBHs + BBHRemnant with precessing and surrogate models
05 GWTC populations GWTC-3/4/5 population sampling, posterior vs prior
06 Retention probability 1G+1G retention heatmaps across kick models
07 Host environments Plummer clusters, escape velocities, environment retention
08 Hierarchical mergers Multi-generation mergers, pairing models, evolving v_esc
09 Seed growth BH seed growth chains, v_esc sweeps, evolving v_esc
10 Displacement & return times Apocentre displacement, dynamical friction return times, GC vs NSC
11 Single-cluster mergers Hierarchical mergers in one cluster: mass/Z/pairing sweeps, evolving v_esc
12 Runaway SMBH progenitor Inferring the progenitor of recoiling SMBH RBH-1 from its kick (flow log_prob inversion)

Citations

If you use this package, please cite the relevant papers:

@article{Islam:2025drw,
    author = "Islam, Tousif and Wadekar, Digvijay",
    title = "{Accurate models for recoil velocity distribution in black hole
              mergers with comparable to extreme mass-ratios and their
              astrophysical implications}",
    eprint = "2511.11536",
    archivePrefix = "arXiv",
    primaryClass = "gr-qc",
    doi = "10.1103/4jvv-qg4h",
    journal = "Phys. Rev. D",
    volume = "113",
    number = "10",
    pages = "104017",
    year = "2026"
}

@article{Islam:2026yxx,
    author = "Islam, Tousif and Wadekar, Digvijay and Kritos, Konstantinos",
    title = "{Kick matters: The impact of a new recoil model on the retention
              of hierarchical black-hole remnants in globular clusters}",
    eprint = "2603.10170",
    archivePrefix = "arXiv",
    primaryClass = "astro-ph.HE",
    month = "3",
    year = "2026"
}

@article{Islam:2026iyn,
    author = "Islam, Tousif",
    title = "{Inference of recoil kicks from binary black hole mergers up to
              GWTC--4 and their astrophysical implications}",
    eprint = "2604.04546",
    archivePrefix = "arXiv",
    primaryClass = "astro-ph.HE",
    month = "4",
    year = "2026"
}

@article{Islam:2026sjl,
    author = "Islam, Tousif and Venumadhav, Tejaswi and Wadekar, Digvijay",
    title = "{Progenitor of the recoiling super-massive black hole RBH-1
              identified using HST/JWST imaging}",
    eprint = "2601.18986",
    archivePrefix = "arXiv",
    primaryClass = "astro-ph.HE",
    month = "1",
    year = "2026"
}

Contact

For questions or issues, please reach out to tousifislam24@gmail.com.

License

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

gwgenealogy-0.1.0.tar.gz (916.8 kB view details)

Uploaded Source

Built Distribution

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

gwgenealogy-0.1.0-py3-none-any.whl (925.7 kB view details)

Uploaded Python 3

File details

Details for the file gwgenealogy-0.1.0.tar.gz.

File metadata

  • Download URL: gwgenealogy-0.1.0.tar.gz
  • Upload date:
  • Size: 916.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.9

File hashes

Hashes for gwgenealogy-0.1.0.tar.gz
Algorithm Hash digest
SHA256 e660c7c38630e922d04e34f2687d1f04c6fdb1be5a86d9bb4cbc5fb2b55f0a18
MD5 4494f512e5fd13e81796acc6b9f43577
BLAKE2b-256 975b4e546cbe3323fafd24fae261e7e6f07d94fab5588c4dc098f03c19fc25f0

See more details on using hashes here.

File details

Details for the file gwgenealogy-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: gwgenealogy-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 925.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.9

File hashes

Hashes for gwgenealogy-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9896c663a47202cdda280214ff5084c05187ac2e1f91ea0bd99a27d2011c2a95
MD5 25bc8748a04ec3ad3535931562827f08
BLAKE2b-256 821187fa3e2aa38b345cb5c76b1eeb82ad3129d43822a0d2be58ea6d920911c2

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