Skip to content

Support hierarchical triple systems with dual binary components (BINARY + BINARY2) - #2011

Open
vhaasteren wants to merge 18 commits into
nanograv:masterfrom
vhaasteren:feat/triple
Open

Support hierarchical triple systems with dual binary components (BINARY + BINARY2)#2011
vhaasteren wants to merge 18 commits into
nanograv:masterfrom
vhaasteren:feat/triple

Conversation

@vhaasteren

@vhaasteren vhaasteren commented Jun 30, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds first-class support for hierarchical triple timing models by allowing two binary delay components in a single PINT model:
    • inner orbit via BINARY with standard parameter names (PB, A1, T0, ...)
    • outer orbit via new BINARY2 with suffixed parameters (PB_2, A1_2, T0_2, ...)
  • Introduces outer-orbit wrapper components (BinaryDD2, BinaryBT2) in a new pulsar_system_outer category, ordered before pulsar_system so outer delay is accumulated first.
  • Preserves physical coupling automatically: the inner binary is evaluated at t_bary - (accumulated delays), so the outer light-travel delay propagates into the inner orbit evaluation epoch.
  • Updates model building/validation/parfile I/O to recognize BINARY2, enforce one inner + one outer binary maximum, and round-trip _2 parameters correctly.
  • Refactors binary base-component parameter access to be suffix-aware (_bp() / _hasbp()), enabling fitting and derivative support for outer-orbit parameters without changing standalone binary calculators.
  • Keeps single-binary behavior unchanged and backward compatible.

Scope / Notes

  • Outer-orbit support currently includes DD and BT wrappers.
  • Outer suffixed orbits intentionally do not support FBn/ORBWAVE parameterizations.
  • This implements coupled delay nesting (not full N-body three-body integration).

Tests

  • Added dedicated triple-system tests covering:
    • component selection and ordering (outer before inner)
    • parameter namespace isolation (PB vs PB_2, etc.)
    • BINARY2 + _2 parfile read/write round-trip
    • finite residuals and non-zero outer contribution
    • propagation of outer delay into inner evaluation epoch
    • coupled solution differs from naive independent sum
    • finite/non-zero derivatives for outer parameters (fitability)
  • Confirmed relevant existing binary/regression tests remain green, including single-binary workflows.

Example

BINARY   DD
PB       ...
A1       ...
T0       ...
...

BINARY2  BT
PB_2     ...
A1_2     ...
T0_2     ...
...

Note: co-developed by @coclar and Claude Code.

Enable a second (outer) binary delay component in a PINT timing model so a
pulsar binary can itself orbit a third body. The outer orbit's delay is
computed before, and propagated into, the inner binary calculation.

- Make PulsarBinary suffix-aware (param_suffix, binary_param_tag, _bp/_hasbp
  helpers, _apply_param_suffix) so a single implementation serves as both the
  inner (canonical params) and outer (_2-suffixed params) component.
- Route pb() and change_binary_epoch() through _bp()/_hasbp() so the inherited
  public methods work on suffixed outer components.
- Add BinaryDD2 and BinaryBT2 outer wrappers (category pulsar_system_outer,
  param_suffix _2, BINARY2 tag).
- Register BINARY2, order pulsar_system_outer before pulsar_system, and handle
  BINARY2 selection / validation in TimingModel and ModelBuilder.
- Add triple-system par file and tests.
Select the primary binary component by binary_param_tag so orbital phase, pulsar radial velocity, and conjunction computations follow the inner BINARY orbit when BINARY2 is also present. Add a triple-system regression test that validates these utilities match the inner-only model and differ from the outer-orbit phase.
@vhaasteren
vhaasteren marked this pull request as draft June 30, 2026 09:03
coclar and others added 15 commits June 30, 2026 14:23
A hierarchical triple's outer orbit imposes a slowly varying Doppler
factor on the inner orbit; over a short data span this appears as
secular changes of the inner A1 beyond the linear A1DOT term. A1DOT2
parameterizes the quadratic term:

    a1(t) = A1 + A1DOT * (t - T0) + 0.5 * A1DOT2 * (t - T0)**2

Changes:
- new A1DOT2 floatParameter (lsec/s^2) on PulsarBinary, frozen at 0
  when unset (BinaryDD.validate, like the other *DOT parameters)
- a1(), d_a1_d_T0, d_a1_d_A1DOT2 and d_Pobs_d_A1DOT2 in the standalone
  PSR_BINARY (d_a1_d_T0 now includes the A1DOT2 chain term)
- d_beta_d_A1DOT2 in DDmodel for symmetry with d_beta_d_A1DOT (the
  generic d_beta_d_par path chains through d_a1_d_par either way)
- tests: A1DOT2 affects the delay; analytic delay derivatives for
  A1DOT2/A1DOT/T0 and outer parameters match finite differences
…t/triple

Keep A1DOT2 with the X2DOT alias and retain local A1DOT2 tests.
Complete BINARY2 support for BT and ELL1 so A1DOT2 and the outer→inner
prev-delay chain rule match finite-difference tests for all three families.
Chain-ruled d_delay_d_param requires SWX ahead of the binary; without
solar_windx in DEFAULT_ORDER it sorted last and broke SW↔SWX fits.
Also harden A1DOT parfile checks and Fermi observatory overwrite.
Compute parameter-independent acc_delays/chain_factors via
delay_deriv_chain and thread them through designmatrix paths, restoring
near-master cost while keeping the binary chain rule. Also harden
triple-aware convert_binary, derived-param summary, and MissingParameter
names.
…t/triple

# Conflicts:
#	src/pint/models/stand_alone_psr_binaries/binary_generic.py
#	tests/test_triple_binary.py
Satisfy CI black --check, note solar_windx DEFAULT_ORDER in the
changelog, and mention BINARY2 in timing-model docs.
Keep MissingParameter/MissingBinaryError/MissingTOAs re-exported from
timing_model (listed in __all__) for existing importers. Remove a dead
unreachable return in binary_generic.
Stop re-exporting them from timing_model; point remaining call sites
at the canonical module.
@vhaasteren
vhaasteren marked this pull request as ready for review July 31, 2026 08:51
Stops collection failure in test_model_manual after Missing* stopped being re-exported from timing_model.
@vhaasteren vhaasteren added enhancement awaiting review This PR needs someone to review it so it can be merged labels Jul 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting review This PR needs someone to review it so it can be merged enhancement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants