Source code for uvex_transients.transients.kilonovae
"""Kilonova (binary neutron star merger) population."""
from typing import Union
import numpy as np
from astropy import units as u
from astropy.units import Quantity
from numpy.typing import NDArray
from uvex_transients.models.kilonovae import KilonovaCoolingBlackbodySED
from .base import ExtragalacticTransient
# Total BNS merger rate (all mass bins, not just the GW170817-like ~1.3+1.3 Msun
# bin), Fishbach et al. 2026: 110 (+192/-82) Gpc^-3 yr^-1. Taken as constant with
# redshift. Using the total BNS rate here means every BNS merger is assumed to
# produce a feasibly GW170817-like kilonova, an assumption made for this
# simulation's convenience and not one asserted by Fishbach et al. 2026 itself
# (whose GW170817-like sub-rate is a strict subset of this total; see their Fig. 2).
_KNE_RATE: Quantity = 110 / (u.Gpc**3 * u.yr)
# The 90% CI endpoints implied by the quoted +192/-82 Gpc^-3 yr^-1, expressed as
# multiplicative factors on `_KNE_RATE` (see `ExtragalacticTransient.RATE_CI`).
_KNE_RATE_CI: tuple[float, float] = ((110 - 82) / 110, (110 + 192) / 110)
[docs]
class Kilonova(ExtragalacticTransient):
r"""
GW170817-like kilonova population.
Modeled with `KilonovaCoolingBlackbodySED` (a Gaussian-rise/broken-power-law-decline
light curve with a cooling blackbody photosphere, calibrated against GW170817), a
constant volumetric rate of :math:`110\ \mathrm{Gpc}^{-3}\,\mathrm{yr}^{-1}` out to
:math:`z=0.2`, and a 30-day duration window. This rate is Fishbach et al. 2026's total
BNS merger rate, not just their GW170817-like mass-bin sub-rate, so every BNS merger
sampled here is assumed to be feasibly GW170817-like: a simplifying assumption of this
simulation, not a claim made by that paper.
The :math:`z=0.2` redshift limit is conservative: a source with bolometric luminosity
below :math:`10^{43}\ \mathrm{erg\,s^{-1}}` (well above anything reported in the
literature) would still remain detectable at UVEX's :math:`m<27` band limit out to
:math:`z=2`, assuming a flat spectrum and no K-correction. The 30-day duration is a
conservative upper bound on the total light curve; the blue/early kilonova component
this SED targets fades below detectability closer to :math:`\sim10` days.
See Also
--------
uvex_transients.models.kilonovae.kne.KilonovaCoolingBlackbodySED : The SED this class pairs with `DEFAULT_MODEL`.
uvex_transients.transients.base.ExtragalacticTransient : The base class supplying rate/sampling machinery.
"""
DEFAULT_MODEL = KilonovaCoolingBlackbodySED
DEFAULT_DURATION = 30 * u.day
DEFAULT_Z_LIM = 0.2
RATE_CI = _KNE_RATE_CI
@property
def rate(self) -> Quantity:
r"""
~astropy.units.Quantity: The volumetric kilonova rate, constant in :math:`z`.
This is Fishbach et al. 2026's total BNS merger rate, taken as a proxy for the
GW170817-like kilonova rate under the assumption that every BNS merger is
feasibly GW170817-like (see module-level comment).
See Also
--------
RATE_CI : The confidence bounds attached to this point estimate.
rate_shape : The redshift dependence this rate normalizes.
"""
return _KNE_RATE
[docs]
def rate_shape(self, z: Union[float, NDArray[np.float64]]) -> Union[float, NDArray[np.float64]]:
r"""
Return the (trivial, constant) rate shape of kilonovae at a given redshift.
Parameters
----------
z : float or array-like
Redshift(s) at which to evaluate the rate shape.
Returns
-------
float or array-like
Ones, since the kilonova rate is constant in :math:`z` (Fishbach et al. 2026).
See Also
--------
rate : The (constant-in-:math:`z`) normalization this shape multiplies.
"""
z = np.asarray(z)
shape = np.ones_like(z, dtype=np.float64)
return shape if z.ndim > 0 else shape.item() # Return scalar if input was scalar.