sage.data.waveform.approximants.IMRPhenomXAS

Filename : IMRPhenomXAS.py Description : GPU-native batched IMRPhenomXAS aligned-spin frequency-domain

waveform model (BBH baseline, no tidal).

Implements the IMRPhenomX aligned-spin (22-mode) waveform entirely in PyTorch, following García-Quirós et al. (2020), arXiv:2001.10914. Inherits device-resident constants from PhenomConstants and adds XAS-specific QNM tables and final mass/spin fits (Jimenez-Forteza et al. 2017, arXiv:1611.00332).

This class is the BBH backbone. Do not use it directly for BNS/NSBH — use IMRPhenomXAS_NRTidalv3 instead.

0 : m1 (solar masses, m1 >= m2) 1 : m2 (solar masses) 2 : chi1z (dimensionless aligned spin of body 1) 3 : chi2z (dimensionless aligned spin of body 2) 4 : distance (Mpc) 5 : tc (s, time of coalescence) 6 : phic (rad, reference orbital phase) 7 : inclination (rad)

Created on 2026-05-27

__author__ = Narenraju Nagarajan __copyright__ = Copyright 2026, Sage __license__ = MIT Licence __version__ = 0.0.1 __maintainer__ = Narenraju Nagarajan __email__ = N/A __status__ = inProgress

References

IMRPhenomXAS : García-Quirós et al. (2020), arXiv:2001.10914 Final spin/mass: Jimenez-Forteza et al. (2017), arXiv:1611.00332 QNM tables : Berti, Cardoso & Will (2009), CQG 26, 163001; arXiv:0905.2975

Classes

IMRPhenomXAS

GPU-native batched IMRPhenomXAS aligned-spin BBH waveform.

Module Contents

class IMRPhenomXAS(f, f_ref, **kwargs)[source]

Bases: sage.data.waveform.approximants.phenom.PhenomConstants

GPU-native batched IMRPhenomXAS aligned-spin BBH waveform.

Inherits scalar constants and PhenomD QNM tables from PhenomConstants. Adds XAS-specific 1200-point QNM tables pre-interpolated to a fine uniform grid for O(1) linear-interpolation at runtime.

Parameters:
  • f (torch.Tensor, shape (B, F)) – Frequency grid in Hz.

  • f_ref (torch.Tensor, shape (B, 1)) – Reference frequency in Hz.

  • **kwargs – Forwarded to PhenomConstants.

f[source]
df[source]
sample_length_in_s[source]
f_numel[source]
f_ref[source]
B[source]
n_pad[source]
hp_buffer[source]
hc_buffer[source]
xas_QNMData_a[source]
xas_QNMData_fring22[source]
xas_QNMData_fdamp22[source]
fM_CUT_XAS[source]
dphase(Mf, phase_coeffs, derived=None)[source]

Evaluate the IMRPhenomXAS phase derivative dΨ₂₂/d(Mf) over the grid.

This is used by get_hphc to compute the time-alignment shift (linb) at Mf = fRING - fDAMP. The returned value is the raw derivative (not scaled by 1/η).

Region definitions match phase().

Parameters:
  • Mf ((B, F) or (B, 1) — dimensionless frequency Mf)

  • phase_coeffs (dict — output of get_phase_coeffs)

  • derived ((B, 13) — unused, kept for API symmetry)

Returns:

dphi

Return type:

(B, F) or (B, 1)

get_hphc(theta, reproduce_lal=False)[source]

Compute FD plus and cross polarisations for a BBH parameter batch.

Parameters:
  • theta (torch.Tensor, shape (B, 8+)) – Columns: [m1, m2, chi1z, chi2z, distance, tc, phic, inclination, …] Masses in solar masses, distance in Mpc, angles in radians.

  • reproduce_lal (bool) – If True, skip FD tapering, tc shift, and df normalisation so the output can be compared directly with raw LALSim output at the same frequency grid.

Returns:

hp, hc – Plus and cross polarisations. The first n_pad bins (DC to f_min) are always zero.

Return type:

torch.Tensor, shape (B, n_pad + F), complex

apply_tc(hp, hc, tc)[source]

Apply a frequency-domain time-shift by tc seconds.

pad_missing_frequencies(hp, hc)[source]

Zero-pad hp/hc from DC to f_min.

get_fcut(M_s)[source]

Physical frequency cutoff in Hz from Mf_CUT = 0.3.

compute_derived_parameters(theta)[source]

Compute mass and spin derived quantities from the parameter batch.

Convention: m1 >= m2 (enforced by the parameter sampler). Mirrors IMRPhenomXSetWaveformVariables in LALSimIMRPhenomX_internals.c.

Parameters:

theta (torch.Tensor, shape (B, 4+)) – Columns 0-3: m1, m2, chi1z, chi2z (masses in solar masses).

Returns:

derived – ┌─────┬───────────────────────────────────────────────────────┐ │ 0 │ m1_s = m1 * GM (seconds) │ │ 1 │ m2_s = m2 * GM │ │ 2 │ M_s = (m1+m2) * GM │ │ 3 │ eta = m1*m2 / M² (symmetric mass ratio) │ │ 4 │ delta = sqrt(1 - 4*eta) (PN asymmetry) │ │ 5 │ Xa = m1/M = 0.5*(1+delta) (dimensionless) │ │ 6 │ Xb = m2/M = 0.5*(1-delta) │ │ 7 │ chiEff = Xa*chi1 + Xb*chi2 │ │ 8 │ chiPNHat (= S in all XAS fits) │ │ 9 │ STotR = (Xa²*chi1 + Xb²*chi2)/(Xa²+Xb²) │ │ 10 │ dchi = chi1 - chi2 │ │ 11 │ chi1 = chi1z (raw aligned spin, body 1) │ │ 12 │ chi2 = chi2z (raw aligned spin, body 2) │ └─────┴───────────────────────────────────────────────────────┘

Return type:

torch.Tensor, shape (B, 13)

static final_mass_2017(eta, S, dchi, delta)[source]

Remnant mass fraction Mfinal / M = 1 − E_rad from the 2017 fit.

Source: XLALSimIMRPhenomXFinalMass2017 in LALSimIMRPhenomXUtilities.c Reference: Jimenez-Forteza et al. (2017), arXiv:1611.00332

Parameters:
  • eta ((B, 1) — symmetric mass ratio)

  • S ((B, 1) — STotR = (Xa²·χ₁ + Xb²·χ₂)/(Xa²+Xb²))

  • dchi ((B, 1) — χ₁ − χ₂)

  • delta ((B, 1) — sqrt(1 − 4η))

Returns:

Mfinal

Return type:

(B, 1) — dimensionless remnant mass fraction (< 1)

static final_spin_2017(eta, S, dchi, delta)[source]

Remnant dimensionless spin a_f from the 2017 fit.

Source: XLALSimIMRPhenomXFinalSpin2017 in LALSimIMRPhenomXUtilities.c Reference: Jimenez-Forteza et al. (2017), arXiv:1611.00332

Parameters:
  • eta ((B, 1) — symmetric mass ratio)

  • S ((B, 1) — STotR = (Xa²·χ₁ + Xb²·χ₂)/(Xa²+Xb²))

  • dchi ((B, 1) — χ₁ − χ₂)

  • delta ((B, 1) — sqrt(1 − 4η))

Returns:

afinal

Return type:

(B, 1) — dimensionless remnant spin ∈ (−1, 1)

Notes

Uses the identity Xa² + Xb² = 1 − 2η to avoid recomputing individual mass fractions (verifiable from Xa = (1+δ)/2).

static get_fRD_fdamp(af, Mfinal)[source]

Return (fRING, fDAMP) in dimensionless Mf units (f_Hz = fRING / M_s).

Uses the rational polynomial fits from LALSimIMRPhenomX_qnm.c (evaluate_QNMfit_fring22 / evaluate_QNMfit_fdamp22), which is what LAL selects at compile-time with QNMfits == 1. The fits are from Berti, Cardoso & Will (2009), CQG 26, 163001; arXiv:0905.2975.

The normalization follows LAL convention:

fRING = evaluate_QNMfit_fring22(afinal) / Mfinal

so that f_physical_Hz = fRING / M_s_total.

Parameters:
  • af (torch.Tensor, shape (B, 1) — final dimensionless spin ∈ [−1, 1])

  • Mfinal (torch.Tensor, shape (B, 1) — remnant mass fraction from final_mass_2017)

Returns:

fRING, fDAMP – Dimensionless frequencies; multiply by 1 / M_s to get Hz.

Return type:

torch.Tensor, shape (B, 1)

static fMECO(eta, chiPNHat, dchi, delta)[source]

Hybrid minimum energy circular orbit (MECO) frequency (dimensionless Mf).

Source: XLALSimIMRPhenomXfMECO in LALSimIMRPhenomXUtilities.c Reference: Cabero et al., Phys.Rev.D95 (2017) 064016.

Parameters:
  • eta ((B, 1) — symmetric mass ratio)

  • chiPNHat ((B, 1) — hatted PN effective spin (used as S in XAS fits))

  • dchi ((B, 1) — χ₁ − χ₂)

  • delta ((B, 1) — sqrt(1 − 4η))

Returns:

fMECO

Return type:

(B, 1) — dimensionless frequency Mf at MECO

static fISCO(afinal)[source]

Innermost stable circular orbit (ISCO) frequency (dimensionless Mf).

Source: XLALSimIMRPhenomXfISCO in LALSimIMRPhenomXUtilities.c Reference: Ori & Thorne, Phys.Rev.D62 (2000) 124022.

Returns the Kerr ISCO orbital frequency OmegaISCO / π normalised to total initial mass, i.e. f_ISCO_Hz = fISCO / M_s.

Parameters:

afinal ((B, 1) — final dimensionless spin)

Returns:

fISCO

Return type:

(B, 1) — dimensionless Mf at ISCO

get_amp_coeffs(derived)[source]

Compute all IMRPhenomXAS amplitude coefficients for the batch.

Mirrors IMRPhenomXGetAmplitudeCoefficients in LALSimIMRPhenomX_internals.c. All versions are fixed to the LAL defaults: InspiralAmpVersion=103, IntermediateAmpVersion=104, RingdownAmpVersion=103.

Parameters:

derived ((B, 13) — output of compute_derived_parameters)

Returns:

ac – Keys (all (B, 1) tensors unless noted): pnTT through pnST, rho1rho3 — inspiral delta0delta4 — intermediate gamma1, gammaR, gammaD2, gammaD13, fRING

— ringdown

fAmpMatchIN, fAmpRDMin — boundaries

Return type:

dict

amp(f_Ms, amp_coeffs, derived)[source]

Evaluate the IMRPhenomXAS normalised amplitude A(Mf) over the grid.

The full FD waveform amplitude is:

|h(f)| = Amp0 * Mf^{-7/6} * A(Mf)

where Amp0 = sqrt(2η/3) * π^{-1/6} and the physical prefactor M_s² / dist_s is applied in get_hphc.

Region definitions (boundary frequencies in Mf units):

Inspiral : Mf ≤ fAmpMatchIN Intermediate: fAmpMatchIN < Mf ≤ fAmpRDMin Ringdown : Mf > fAmpRDMin

Inspiral ansatz (Eq. 5.2 of arXiv:2001.11412):
A_ins(Mf) = 1 + pnTT·Mf^{2/3} + pnThT·Mf + pnFoT·Mf^{4/3}
  • pnFiT·Mf^{5/3} + pnST·Mf²

  • ρ₁·Mf^{7/3} + ρ₂·Mf^{8/3} + ρ₃·Mf³

Intermediate ansatz (Eq. 6.12):

A_int(Mf) = Mf^{7/6} / (δ₀ + δ₁·Mf + δ₂·Mf² + δ₃·Mf³ + δ₄·Mf⁴)

Ringdown ansatz (Eq. 6.17):
A_rd(Mf) = γ₁·fDAMP·γ₃ · exp(-(Mf-fRING)·γ₂/(fDAMP·γ₃))

/ ((Mf-fRING)² + (fDAMP·γ₃)²)

Parameters:
  • f_Ms ((B, F) — dimensionless frequency grid Mf = f·M_s)

  • amp_coeffs (dict — output of get_amp_coeffs)

  • derived ((B, 13) (unused here; kept for API symmetry))

Returns:

amp

Return type:

(B, F) — normalised amplitude A(Mf)

get_phase_coeffs(derived)[source]

Compute all IMRPhenomXAS phase coefficients for the batch.

Mirrors IMRPhenomXGetPhaseCoefficients + IMRPhenomX_Phase_22_ConnectionCoefficients in LALSimIMRPhenomX_internals.c. Fixed to default LAL flags:

IMRPhenomXInspiralPhaseVersion = 104 IMRPhenomXIntermediatePhaseVersion = 104 IMRPhenomXRingdownPhaseVersion = 105

Parameters:

derived ((B, 13) — output of compute_derived_parameters)

Returns:

pc

inspiral: phi0..phi9L (PN integrals),

sigma1..sigma5 (pseudo-PN integral coefficients), a0..a3 (pseudo-PN derivative coefficients), phiNorm, dphase0

intermediate: b0..b4 ringdown: c0, c1, c2, c4, cL, cLovfda, c4ov3 boundaries: fPhaseMatchIN, fPhaseMatchIM continuity: C1Int, C2Int, C1MRD, C2MRD

Return type:

dict — all tensors (B, 1) unless noted:

phase(f_Ms, phase_coeffs, derived)[source]

Evaluate the raw IMRPhenomXAS phase Ψ₂₂(Mf) over the frequency grid.

Does NOT apply the 1/η re-scaling or the tc/phic offsets — those are handled in get_hphc. The full FD phase used to build h(f) is:

phi_total = (1/η) * Ψ₂₂(Mf) + linb*Mf + phifRef

where linb is the time-alignment shift and phifRef is the reference phase (both computed in get_hphc).

Region definitions:

Inspiral : Mf < fPhaseMatchIN Intermediate : fPhaseMatchIN ≤ Mf < fPhaseMatchIM Ringdown : Mf ≥ fPhaseMatchIM

Inspiral ansatz integral (Eq. 7.4 of arXiv:2001.11412):

phiNorm * Mf^{-5/3} * [phi0 + phi1*Mf^{1/3} + … + sigma1*Mf^{8/3} + …]

Intermediate ansatz integral (Eq. 7.7, case 105):

b0*Mf + b1*log(Mf) - b2/Mf - b3/(2*Mf²) - b4/(3*Mf³) + (2*cL/fDAMP)*atan((Mf-fRING)/(2*fDAMP)) + C1Int + C2Int*Mf

Ringdown ansatz integral (Eq. 7.12):

c0*Mf + 1.5*c1*Mf^{2/3} - c2/Mf - (c4/3)*Mf^{-3} + (cL/fDAMP)*atan((Mf-fRING)/fDAMP) + C1MRD + C2MRD*Mf

Parameters:
  • f_Ms ((B, F) — dimensionless frequency grid Mf = f·M_s)

  • phase_coeffs (dict — output of get_phase_coeffs)

  • derived ((B, 13) (unused here; kept for API symmetry))

Returns:

psi

Return type:

(B, F) — raw phase Ψ₂₂(Mf) in radians