Skip to content

lalsimutils: fix spurious (l,±m) asymmetry in hlmoft FD-mode conditioning - #163

Open
oshaughnessy-junior wants to merge 1 commit into
oshaughn:masterfrom
oshaughnessy-junior:lalsimutils-fdmode-parity-fix
Open

lalsimutils: fix spurious (l,±m) asymmetry in hlmoft FD-mode conditioning#163
oshaughnessy-junior wants to merge 1 commit into
oshaughn:masterfrom
oshaughnessy-junior:lalsimutils-fdmode-parity-fix

Conversation

@oshaughnessy-junior

Copy link
Copy Markdown

Single-commit replacement for #162 (which accidentally carried the whole development-branch history; closing it in favor of this).

Summary

RIFT's hlmoft ChooseFDModes→TD conditioning introduced spurious (±m) mode asymmetry at the ~1% level for every ChooseFDModes-consumed model (IMRPhenomXHM/XPHM/XPNR/XO4a/HM): an exactly-symmetric aligned-spin IMRPhenomXHM input acquired 1.02% (2,±2) and 0.9% (3,±3) relative amplitude asymmetry, violating the conjugate-pair identity h_{l,-m}(f) = (-1)^l conj(h_{lm}(-f)).

Root cause: SimInspiralChooseFDModes returns modes on an ascending two-sided grid [−fNyq, +fNyq] with DC at the center index (odd length TDlen+1), but the FD high-pass window assigned frequencies via evaluate_fvals, which assumes RIFT's reversed packing and, at odd length, gives f_assumed = −f_true + deltaF/2. Since (l,m) and (l,−m) modes occupy opposite signs of f, the nominally |f|-symmetric window landed one bin apart on the two members of each pair — precisely in the taper band [0.964·fmin, fmin] containing the |h̃(f)| maximum.

Fix: build the window on the true frequency grid (P.deltaF*(np.arange(npts) - npts//2), exactly even in f), and zero the −fNyq bin left unpaired when the resize truncates its +fNyq partner, so all conditioning commutes with complex conjugation. All other conditioning stages (start/end tapers, centering roll, IFFT) are covariant already.

Verification

Nonprec control (m1=44, m2=36 Msun, s1z=0.5, s2z=−0.3, fmin=fref=20, deltaF=1/16, deltaT=1/4096), rerun against this branch (master + this commit):

  • Raw ChooseFDModes XHM satisfies the conjugate-pair identity exactly (0.0); through hlmoft the mode-level residual drops 1.02e-2 → 2.5e-16. IMRPhenomHM and XPNR machine-exact; XPHM reduced to its intrinsic 4.4e-3 (2,±1) aligned-spin model asymmetry; precessing XPHM amplitude identity at 4.2e-16.
  • U/V-level diagnostics: D2 1.04e-9 → 1.28e-17, D3 1.7e-9 → 1.4e-16. (The corrupted band lies mostly below fmin, so the U/V-level leakage was ~1e-9, not the mode-level 1e-2; the fix removes the interface floor entirely.)
  • Conditioned-waveform change: 1.1e-2 full-band, 99% of it below fmin in the discarded turn-on band; 1.6e-3 in-band (corrected window-edge placement at fmin).

The parity QA scripts used for verification live on the fork's rift_O4d branch under MonteCarloMarginalizeCode/Code/test/waveforms/ (merged there via oshaughnessy-junior#52).

🤖 Generated with Claude Code

@oshaughnessy-junior
oshaughnessy-junior force-pushed the lalsimutils-fdmode-parity-fix branch from 03549f9 to c17c93f Compare August 7, 2026 21:55
@oshaughnessy-junior

Copy link
Copy Markdown
Author

Addressed in the amended commit (c17c93f): the -fNyq zeroing is now guarded by whether the resize actually truncated (npts_fd_pre_resize > TDlen) rather than by not(no_condition), so the raw diagnostic path is covariant too. Verified both paths at machine precision (worst conjugate-pair residual 3.3e-16 conditioned, 3.5e-16 with no_condition=True, XHM nonprec control).

…ning

SimInspiralChooseFDModes returns modes on an ascending two-sided grid
[-fNyq, +fNyq] with DC at the center index (odd length TDlen+1), but the
FD high-pass window in hlmoft assigned frequencies via evaluate_fvals,
which assumes RIFT's reversed packing and, at odd length, is offset by
deltaF/2 (f_assumed = -f_true + deltaF/2).  Because (l,m) and (l,-m)
modes occupy opposite signs of f, the 'symmetric' window was shifted by
one bin between the members of each pair -- exactly in the taper band
containing the |h(f)| maximum -- violating the conjugate-pair identity
h_{l,-m}(f) = (-1)^l conj(h_{lm}(-f)) for every ChooseFDModes-consumed
model (IMRPhenomXHM/XPHM/XPNR/XO4a/HM), e.g. 1.02% (2,±2) amplitude
asymmetry for an exactly-symmetric aligned-spin XHM input.

Build the window on the true frequency grid (exactly even in f), and
zero the surviving -fNyq bin when the resize truncates its +fNyq
partner, so all conditioning commutes with complex conjugation.

Verification (nonprec control, M=80, fmin=fref=20, deltaF=1/16):
- mode-level TD conjugate-pair residual: 1.02e-2 -> 2.5e-16 (XHM);
  XPNR and HM machine-exact; XPHM reduced to its intrinsic model
  asymmetry; precessing XPHM amplitude identity at 4.2e-16.
- U/V diagnostics (test/waveforms/uv_parity_diagnostics.py):
  D2 1.04e-9 -> 1.28e-17, D3 1.7e-9 -> 1.4e-16.  (The corrupted band
  lay mostly below fmin, so U/V leakage was ~1e-9, not the mode-level
  1e-2; the fix removes the interface floor entirely.)
- Conditioned waveform change: 1.1e-2 full-band, 99% of it below
  fmin in the discarded turn-on band; 1.6e-3 in-band.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@oshaughnessy-junior
oshaughnessy-junior force-pushed the lalsimutils-fdmode-parity-fix branch from c17c93f to 06764da Compare August 8, 2026 08:45
@oshaughnessy-junior

Copy link
Copy Markdown
Author

Style point addressed in the amended commit (06764da): the grid choice now lives in evaluate_fvals(lal_2sided_fseries, lal_convention=False/True) — default False keeps the existing reversed-RIFT packing byte-identical; True returns the LAL-generator packing f[k] = deltaF*(k - npts//2) (exact for even and odd lengths), with docstring notes on when each applies and what goes wrong if you use the default on ChooseFDModes output. hlmoft now calls evaluate_fvals(..., lal_convention=True) instead of building the grid inline. No behavior change: XHM nonprec conjugate-pair residual still 3.3e-16.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants