Skip to content

potential/backend: anchor scalar coordinates in migrated analytic/disk compute methods#992

Open
jobovy wants to merge 1 commit into
feat/backendsfrom
backend/potential-scalar-anchor
Open

potential/backend: anchor scalar coordinates in migrated analytic/disk compute methods#992
jobovy wants to merge 1 commit into
feat/backendsfrom
backend/potential-scalar-anchor

Conversation

@jobovy

@jobovy jobovy commented Jun 21, 2026

Copy link
Copy Markdown
Owner

What

Anchor scalar/numpy coordinate operands onto the active backend at the start of the migrated compute methods of 5 potentials (SpiralArmsPotential, EllipticalDiskPotential, KuijkenDubinskiDiskExpansionPotential, PowerSphericalPotential, PowerSphericalPotentialwCutoff), via the established per-method coerce_coords convention (the same one EllipsoidalPotential._anchor_phi uses).

These methods feed coordinates straight to xp.<fn> (cos/sin/exp/sqrt/log/abs/sign), which torch rejects on a python-float / numpy.float64 / numpy.ndarray. #990's potential_physical_input boundary coercion covers the public array-evaluation path for backend-compatible potentials, but it is bypassed by:

  • direct private-method calls (the test_2ndDeriv / test_forceAsDeriv numerical-derivative path through undecorated mock wrappers),
  • the internal axisymmetric phi = 0 reset (mockFlatEllipticalDisk),
  • parameter/t forwarding (kuijkendubinski_t_forwarding).

Result — 6 genuine torch reds flipped

test_2ndDeriv_potential[CorotatingRotation3DSpiralArmsPotential]
test_forceAsDeriv_potential[CorotatingRotation3DSpiralArmsPotential]
test_2ndDeriv_potential[mockFlatEllipticalDiskPotential]
test_amp_mult_divide[mockFlatEllipticalDiskPotential]
test_forceAsDeriv_potential[mockFlatEllipticalDiskPotential]
test_kuijkendubinski_t_forwarding

(verified fail-without / pass-with under forced torch, regen mode.)

PowerSpherical / PowerSphericalwCutoff flip no currently-red entry — #990's boundary masks their direct-compute-method gap — but they were migrated before this convention existed, so they're brought to per-method coerce_coords parity (byte-identical; closes the latent direct-call torch gap). Honest defense-in-depth, not a red-flip.

Safety (adversarially reviewed — two independent passes)

  • numpy byte-identicalcoerce_coords is an object-identical pass-through when xp is numpy; verified identical SHA-256 output hashes across all 5 families (incl. the KuijkenDubinski lambda→def closure conversion, which is behaviorally identical).
  • jax value-identical — worst diff 3.95e-14 across the 5 families.
  • Coverage — the new coerce_coords lines execute on the numpy test_potential path (build.yml numpy jobs, coverage-uploaded); no backend-only line.
  • Altitude — per-method is correct: the bypass is the mock/direct-private layer, not a galpy mixin; there is no shared choke point for these 5 potentials.
  • No ledger change (the 6 become XPASS, green via strict=False; pruned in the separate ledger-regen PR).

File-disjoint from #991 (_coerce.py/_namespaces.py). Base is current feat/backends (#990).

Out of scope (separate follow-ups the review surfaced)

  • expwholeDiskMultipoleExpansionPotential 2ndDeriv — a construction-time numpy.ndarray * Tensor in MultipoleExpansionPotential.from_density (Finalize pvz etc. functions #75-adjacent).
  • specialSpiralArmsPotential 2ndDeriv — a torch finite-difference precision mismatch, not a scalar crash.
  • The larger _backend_compatible mock-bypass cluster (DehnenBar / Ferrers / SoftenedNeedleBar / …) — same vector, each needs its own per-method audit.

🤖 Generated with Claude Code

…k compute methods

The migrated compute methods of these potentials feed coordinate operands
straight to xp.<fn> (xp.cos/sin/exp/sqrt/log/abs/sign), which torch rejects on a
python-float / numpy.float64 / numpy.ndarray. #990's potential_physical_input
boundary coercion covers the public array-evaluation path for backend-compatible
potentials, but it is BYPASSED by (a) the numerical-derivative mixin and other
DIRECT private-method calls (test_2ndDeriv / test_forceAsDeriv), (b) the internal
axisymmetric phi=0 reset (mockFlatEllipticalDisk), and (c) parameter/t forwarding
(KuijkenDubinski). Coerce the operands at the start of each compute method via
coerce_coords -- the established per-method convention the already-migrated
potentials use (e.g. EllipsoidalPotential._anchor_phi).

Flips 6 ledgered torch entries that bypass the #990 boundary:
  test_2ndDeriv_potential[CorotatingRotation3DSpiralArmsPotential]
  test_forceAsDeriv_potential[CorotatingRotation3DSpiralArmsPotential]
  test_2ndDeriv_potential[mockFlatEllipticalDiskPotential]
  test_amp_mult_divide[mockFlatEllipticalDiskPotential]
  test_forceAsDeriv_potential[mockFlatEllipticalDiskPotential]
  test_kuijkendubinski_t_forwarding

Also brings PowerSpherical / PowerSphericalwCutoff to the same per-method
coerce_coords parity (migrated before the convention existed). These flip no
currently-red entry -- #990's boundary masks their direct-compute-method gap --
but the fix closes that gap and is byte-identical, so it is convention-parity
hardening rather than a red-flip.

numpy path is byte-identical (coerce_coords is an object-identical pass-through
when xp is numpy; verified identical output hashes across the 5 files). jax
value-identical (25 entries pass under jax). The new coerce_coords lines execute
on the numpy test_potential path (coverage-uploaded). No ledger change (the 6
become XPASS, green via strict=False; pruned in the separate ledger-regen PR).

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

codecov Bot commented Jun 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.93%. Comparing base (38dad76) to head (e0532c0).

Additional details and impacted files
@@              Coverage Diff               @@
##           feat/backends     #992   +/-   ##
==============================================
  Coverage          99.93%   99.93%           
==============================================
  Files                254      254           
  Lines              39839    39897   +58     
  Branches             839      839           
==============================================
+ Hits               39813    39871   +58     
  Misses                26       26           

☔ 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.

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