Skip to content

P2.3 Ellipsoidal/triaxial potentials: backend-agnostic namespace-swap#895

Merged
jobovy merged 3 commits into
feat/backendsfrom
feat/P2.3-ellipsoidal
Jun 7, 2026
Merged

P2.3 Ellipsoidal/triaxial potentials: backend-agnostic namespace-swap#895
jobovy merged 3 commits into
feat/backendsfrom
feat/P2.3-ellipsoidal

Conversation

@jobovy

@jobovy jobovy commented Jun 4, 2026

Copy link
Copy Markdown
Owner

Part of the P2.x potential namespace-swap series (→ #892).

Migrated: EllipsoidalPotential base (all force/2nd-deriv/dens + the Gauss-Legendre quadrature path) + PerfectEllipsoid, PowerTriaxial, TriaxialGaussian/Hernquist/Jaffe/NFW, TwoPowerTriaxial (forces/2nd-derivs/dens).
Key refactor: the mutable per-instance quadrature cache (_force_hash/_cached_Fx…) is now read/written only when get_namespace(...) is numpy; the traced (jax/torch) path computes the shared GL integral as a pure local and never touches self-state (verified by cache-isolation tests). coords.cyl_to_rect + the rotation matmul inlined as backend-agnostic arithmetic.
Deferred: _mass (scipy.integrate/special), the scipy.integrate fallback quadrature path, TwoPowerTriaxial _evaluate (hyp2f1).
Tests: tests/test_backend_ellipsoidal.py — 258 passed (parity + grad-vs-FD + cache-isolation). Numpy byte-identical incl. rotated cases.

🤖 Generated with Claude Code

@codecov

codecov Bot commented Jun 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.92%. Comparing base (141ebfe) to head (ee06712).
⚠️ Report is 3 commits behind head on feat/backends.

Additional details and impacted files
@@               Coverage Diff               @@
##           feat/backends     #895    +/-   ##
===============================================
  Coverage          99.92%   99.92%            
===============================================
  Files                228      228            
  Lines              34213    34941   +728     
  Branches             712      714     +2     
===============================================
+ Hits               34186    34914   +728     
  Misses                27       27            

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jobovy jobovy force-pushed the feat/P2.3-ellipsoidal branch from a579adf to 99e9be4 Compare June 5, 2026 17:20
@jobovy jobovy marked this pull request as ready for review June 6, 2026 01:08
jobovy and others added 2 commits June 6, 2026 11:22
… tests

Complete the backend-agnostic migration of the ellipsoidal/triaxial family
beyond the main compute methods done in the prior commit:

- Migrate the CLOSED-FORM _mass methods to the backend namespace:
  * PerfectEllipsoidPotential._mass: numpy.arctan -> xp.atan, numpy.pi -> math.pi
  * TriaxialNFWPotential._mass: numpy.log -> xp.log, numpy.pi -> math.pi
  * TriaxialHernquistPotential / TriaxialJaffePotential._mass: numpy.pi -> math.pi
  These now run and differentiate under numpy / jax / torch (values bit-identical
  to before: math.pi == numpy.pi, numpy.atan/log are the same ufuncs).

- Leave (and explicitly annotate as Pspecial-blocked) the _mass methods with no
  backend-agnostic replacement:
  * TwoPowerTriaxialPotential._mass / _psi / __init__: scipy.special.hyp2f1, gamma
  * TriaxialGaussianPotential._mass: scipy.special.erf
  * EllipsoidalPotential._mass (generic, incl. PowerTriaxial): scipy.integrate.quad
  The Gauss-Legendre compute path was already migrated; the glorder=None
  scipy.integrate fallback stays deferred. The init-time amp/rotation setup and
  the numpy-gated quadrature hash cache remain numpy by design.

- Tests (tests/test_backend_ellipsoidal.py):
  * numpy-vs-jax-vs-torch parity + grad-vs-FD for the four migrated closed-form
    _mass methods.
  * ROTATED (zvec/pa) value-parity coverage for the rotated compute path
    (forces / phitorque / dens / migrated _evaluate) across all subclasses, plus
    rotated _evaluate grad-vs-FD — the rotated path previously had no coverage.

All 393 backend-ellipsoidal tests pass under numpy+jax+torch; numpy potential
mass/triaxial sanity tests unchanged.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…ntities

Replace the finite-difference autodiff checks (test_grad_evaluate /
test_grad_rforce vs FD, rtol 1e-5) with exact analytic-identity checks at
rtol=1e-9. Under galpy's sign conventions autodiff of a lower-order quantity
equals the negative of the corresponding analytic higher-order quantity:

  AD(_evaluate wrt R/z/phi)   == -_Rforce / -_zforce / -_phitorque
  AD(_Rforce  wrt R/z/phi)    == -_R2deriv / -_Rzderiv / -_Rphideriv
  AD(_zforce  wrt z/phi)      == -_z2deriv / -_phizderiv
  AD(_phitorque wrt phi)      == -_phi2deriv

These hold to round-off (lower and higher share the same Gauss-Legendre
quadrature nodes), so they cross-validate the hand-coded triaxial forces and
the phi-dependent Hessian, far more stringently than finite differences.

The new parametrized test (potentials x AD_BACKENDS x identity pairs) gates each
pair on both methods being namespace-migrated: the six force/2nd-derivative pairs
run for every potential (they depend only on the pure-arithmetic _mdens), while
the three _evaluate pairs are skipped for TwoPowerTriaxialPotential (its _psi
uses scipy.special.hyp2f1 and is Pspecial-deferred). 60 identity tests per AD
backend (54 for the six eval-migrated potentials + 6 force/Hessian pairs for
TwoPower). The mass-gradient and rotated-frame FD checks are kept (no analytic
counterpart). Green on numpy + jax + torch.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
@jobovy jobovy merged commit f5586f7 into feat/backends Jun 7, 2026
108 checks passed
@jobovy jobovy deleted the feat/P2.3-ellipsoidal branch June 7, 2026 13:23
jobovy added a commit that referenced this pull request Jun 10, 2026
…#895)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jobovy added a commit that referenced this pull request Jun 12, 2026
…#895)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jobovy added a commit that referenced this pull request Jun 13, 2026
…#895)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jobovy added a commit that referenced this pull request Jun 15, 2026
…#895)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jobovy added a commit that referenced this pull request Jun 17, 2026
…#895)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jobovy added a commit that referenced this pull request Jun 19, 2026
…#895)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jobovy added a commit that referenced this pull request Jun 19, 2026
…#895)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jobovy added a commit that referenced this pull request Jun 25, 2026
…#895)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant