Retention Probability Over the (chi, q) Plane

Compute and visualize \(P_{\rm ret}(q, \chi_{\rm max}, v_{\rm esc})\) for 1G+1G BBH mergers using BBHRetentionProbabilityOverChiq. Reproduces Figure 2 of Islam, Wadekar & Kritos (2026, arXiv:2603.10170).

[1]:
import warnings
warnings.filterwarnings('ignore', 'Wswiglal-redir-stdio')

from gwGenealogy.core import BBHRetentionProbabilityOverChiq
from gwGenealogy.utils import set_rcparams
import numpy as np
import matplotlib.pyplot as plt

set_rcparams()
lal.MSUN_SI != Msun

HLZ kick model

Sweep \(q \in [1, 10]\), \(\chi_{\rm max} \in [0.01, 1]\) at four escape velocities.

[2]:
grid_hlz = 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'],
    n_samples=10000, seed=42)
print(grid_hlz)
results_hlz = grid_hlz.compute(verbose=True)
BBHRetentionProbabilityOverChiq(q=[1.0,10.0]x50, chi=[0.01,1.00]x50, v_esc=[np.float64(50.0), np.float64(100.0), np.float64(200.0), np.float64(500.0)], models=['hlz'], spin=uniform, n=10000)
  250/2500 grid points done
  500/2500 grid points done
/Users/tousifislam/Research/projects/stupid/refactor_gwModels/gwModels/gwModels/remnants/HBR_mass_spin.py:187: RuntimeWarning: invalid value encountered in sqrt
  chi_final = np.sqrt(term1 + term2 + term3) / (1.0 + small_q)**2
  750/2500 grid points done
  1000/2500 grid points done
  1250/2500 grid points done
  1500/2500 grid points done
  1750/2500 grid points done
  2000/2500 grid points done
  2250/2500 grid points done
  2500/2500 grid points done
[3]:
fig, axes = grid_hlz.plot_heatmap_all_vesc()
plt.show()
/Users/tousifislam/Research/projects/stupid/gwGenealogy/gwGenealogy/core/retention.py:261: UserWarning: This figure includes Axes that are not compatible with tight_layout, so results might be incorrect.
  plt.tight_layout(rect=[0, 0, 0.88, 1])
../_images/notebooks_06_retention_probability_4_1.png

Single panel: \(v_{\rm esc} = 200\) km/s

[4]:
fig, ax, im = grid_hlz.plot_heatmap('hlz', 200)
fig.colorbar(im, ax=ax, label=r'$p_{\rm ret}$')
plt.show()
../_images/notebooks_06_retention_probability_6_0.png

HLZ vs gwModel comparison

Run both kick models on the same grid with shared isotropic angles. The plot_heatmap_all_vesc() method shows v_esc rows x model columns.

Note: gwModel uses a normalizing flow that evaluates per-sample, so we use a coarser grid (10x10) with fewer samples (1000) here for speed.

[5]:
grid_both = BBHRetentionProbabilityOverChiq(
    q_values=np.linspace(1, 10, 10),
    chi_max_values=np.linspace(0.01, 1, 10),
    v_esc_values=[50, 100, 200, 500],
    kick_models=['hlz', 'gwmodel'],
    n_samples=1000, seed=42)
print(grid_both)
results_both = grid_both.compute(verbose=True)
BBHRetentionProbabilityOverChiq(q=[1.0,10.0]x10, chi=[0.01,1.00]x10, v_esc=[np.float64(50.0), np.float64(100.0), np.float64(200.0), np.float64(500.0)], models=['hlz', 'gwmodel'], spin=uniform, n=1000)
  10/100 grid points done
  20/100 grid points done
  30/100 grid points done
  40/100 grid points done
  50/100 grid points done
  60/100 grid points done
  70/100 grid points done
  80/100 grid points done
  90/100 grid points done
  100/100 grid points done
[6]:
fig, axes = grid_both.plot_heatmap_all_vesc()
plt.show()
/Users/tousifislam/Research/projects/stupid/gwGenealogy/gwGenealogy/core/retention.py:261: UserWarning: This figure includes Axes that are not compatible with tight_layout, so results might be incorrect.
  plt.tight_layout(rect=[0, 0, 0.88, 1])
../_images/notebooks_06_retention_probability_9_1.png