Skip to content

✨ feat(charts): correct & complete PoincarePolar6D (symplectic phase-space chart + gala transform)#587

Open
nstarman wants to merge 3 commits into
GalacticDynamics:mainfrom
nstarman:claude/v024-poincarepolar6d
Open

✨ feat(charts): correct & complete PoincarePolar6D (symplectic phase-space chart + gala transform)#587
nstarman wants to merge 3 commits into
GalacticDynamics:mainfrom
nstarman:claude/v024-poincarepolar6d

Conversation

@nstarman

@nstarman nstarman commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Summary

Makes PoincarePolar6D correct and usable.

1. Fix the chart declaration

The 5th coordinate dt_pp_phi was declared length/time**1.5 (a literal "d/dt of pp_phi" reading). Per gala's cartesian_to_poincare_polar (Papaphilippou & Laskar 1996) it's the symplectic quadrature partner √(2|Lz|)·sin(φ), same length/time**0.5 dimension as pp_phi. Confirmed with the maintainer that gala's symplectic (q, p) object is intended.

  • rename dt_pp_phipp_phidot; fix its dimension to length/time**0.5
  • document as Poincaré symplectic-polar variables on T*ℝ³; why M = no_manifold (symplectic, no Riemannian metric) and no global Cartesian chart
  • drop stale # TODO: actual manifold markers

2. Forward + partial-inverse pt_map (both directions)

Between a two-factor Cartesian product chart (cart3d × cart3d = [position, velocity]) and PoincarePolar6D — reusing the existing product chart, no new public chart.

  • forward (gala's map): rho=hypot(x,y), phi=atan2(x,y), Lz=x*vy−y*vx, pp_phi=√(2|Lz|)cos φ, pp_phidot=√(2|Lz|)sin φ, dt_rho=(x*vx+y*vy)/rho, dt_z=vz
  • inverse (derived): solves the 2×2 for (vx,vy). Since √|Lz| drops sign(Lz), it assumes Lz ≥ 0 and is a partial inverse — position always round-trips, velocity sign is lost for Lz < 0.

Non-(Cart3D, Cart3D) product sources/targets raise NotImplementedError.

Verification

Known-value + round-trip doctests (symplectic quadratures, both directions, the guard); tests/unit/charts passes (443); module doctests pass (298); ruff/ty clean.

🤖 Generated with Claude Code

PoincarePolar6D declared its 5th coordinate `dt_pp_phi` with dimension
`length/time**1.5` (a literal d/dt of `pp_phi` reading). But the authoritative
definition — gala's `cartesian_to_poincare_polar` (Papaphilippou & Laskar 1996,
A&A 307, 427) — makes it the *symplectic quadrature partner*
`sqrt(2|Lz|)*sin(phi)`, with the SAME `length/time**0.5` dimension as `pp_phi`,
not its time derivative. The `time**1.5` unit and `dt_` name were a placeholder
inconsistency.

* rename component `dt_pp_phi` -> `pp_phidot` (gala's `p_phi_dot`)
* fix its dimension `length/time**1.5` -> `length/time**0.5`
* document the chart as Poincaré *symplectic-polar* variables on phase space
  `T*R^3`, why it has no Riemannian metric (`M = no_manifold`: phase space is
  symplectic, `metric_matrix` is inapplicable) and no global Cartesian chart,
  and the forward-only / sign(Lz)-ambiguity caveat
* drop the stale `# TODO: actual manifold` markers (no_manifold is correct)

Updates the predefined-chart test and spec.md accordingly. (The gala forward
transform from a Cartesian phase-space source chart is a follow-up: it needs a
new 6D phase-space chart, which does not exist yet.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 25, 2026 03:05
@github-actions github-actions Bot added 📝 Add / update documentation Add or update documentation. ✅ Add / update / pass tests Add, update, or pass tests. 🐛 Fix a bug Fix a bug. labels Jul 25, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request corrects the PoincarePolar6D predefined 6D chart so its 5th coordinate matches the intended symplectic quadrature partner used by gala’s Poincaré variables (rather than a misinterpreted time-derivative placeholder), aligning component naming, units, tests, and the authoritative spec.

Changes:

  • Renamed the 5th component from dt_pp_phi to pp_phidot and updated its dimension to length / time**0.5.
  • Updated PoincarePolar6D docstring to describe the symplectic-polar phase-space interpretation and the deliberate no_manifold choice (no metric / no metric_matrix).
  • Updated the predefined-chart unit test and docs/spec.md to match the corrected components/dimensions.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
tests/unit/charts/test_predef_charts.py Updates the expected component name and dimension for the predefined poincarepolar6d chart.
src/coordinax/_src/charts/d6.py Renames the chart component key, corrects its dimension, and revises documentation/comments for the symplectic phase-space meaning.
docs/spec.md Updates the authoritative spec’s component list and coordinate dimensions for PoincarePolar6D.

@codecov

codecov Bot commented Jul 25, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.11765% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.66%. Comparing base (b6aa5dd) to head (caa6ae3).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/coordinax/_src/charts/register_ptmap.py 93.54% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #587      +/-   ##
==========================================
- Coverage   94.66%   94.66%   -0.01%     
==========================================
  Files         247      247              
  Lines        7894     7925      +31     
==========================================
+ Hits         7473     7502      +29     
- Misses        421      423       +2     

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

…arePolar6D

Register the pt_map from a two-factor Cartesian product chart (cart3d x cart3d =
[position, velocity]) to PoincarePolar6D, implementing gala's
cartesian_to_poincare_polar (Papaphilippou & Laskar 1996):

  rho = hypot(x, y);  phi = atan2(x, y)  [gala azimuth convention]
  Lz = x*vy - y*vx;  s = sqrt(2|Lz|)
  pp_phi = s*cos(phi);  pp_phidot = s*sin(phi)
  dt_rho = (x*vx + y*vy)/rho;  dt_z = vz

Reuses the existing product chart as the source (no new public chart). Forward
only — sqrt(|Lz|) drops sign(Lz), so there is no inverse (matching gala). A
non-(Cart3D, Cart3D) product source raises NotImplementedError. Known-value
doctest covers the symplectic quadratures and the guard.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 25, 2026 14:39
@nstarman nstarman changed the title 🐛 fix(charts): correct PoincarePolar6D as a symplectic phase-space chart ✨ feat(charts): correct & complete PoincarePolar6D (symplectic phase-space chart + gala transform) Jul 25, 2026
@github-actions github-actions Bot added the ✨ Introduce new features Introduce new features. label Jul 25, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

docs/spec.md:1692

  • The spec still says the only in-core transition behavior is the identity transform, but this PR also registers a new forward pt_map from Cartesian phase space (cart3d × cart3d product) to PoincarePolar6D. The spec should be updated so it remains the authoritative source of truth for supported transitions.
    - `poincarepolar6d` is the pre-defined `PoincarePolar6D()` instance.
    - Transition behavior currently registered in-core:
      identity transform only (`pt_map(p, PoincarePolar6D, PoincarePolar6D) -> p`).
    - No dedicated Cartesian projection dispatch is currently defined for this chart family.

Comment on lines +1778 to +1781
del usys
if len(from_chart.factors) != 2 or not all(
isinstance(f, Cart3D) for f in from_chart.factors
):
Comment on lines +1793 to +1804
rho = jnp.hypot(x, y)
phi = jnp.atan2(x, y) # gala convention: azimuth from +y
lz = x * vy - y * vx
s = jnp.sqrt(2 * jnp.abs(lz))
return {
"rho": rho,
"pp_phi": s * jnp.cos(phi),
"z": z,
"dt_rho": (x * vx + y * vy) / rho,
"pp_phidot": s * jnp.sin(phi),
"dt_z": vz,
}
Adds the reverse pt_map (PoincarePolar6D -> cart3d x cart3d), derived
algebraically from the forward gala map:

  s = hypot(pp_phi, pp_phidot);  phi = atan2(pp_phidot, pp_phi);  Lz = s**2/2
  x = rho sin(phi);  y = rho cos(phi);  z = z
  vx = sin(phi) dt_rho - cos(phi) Lz/rho
  vy = cos(phi) dt_rho + sin(phi) Lz/rho;  vz = dt_z

Partial inverse: the forward's sqrt(2|Lz|) discards sign(Lz), so this assumes
Lz >= 0 and is exact only for non-negative-Lz points (position always
round-trips; velocity sign is lost otherwise). Guards a non-(Cart3D, Cart3D)
target with NotImplementedError. Round-trip doctest included.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 25, 2026 14:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (3)

src/coordinax/_src/charts/register_ptmap.py:1782

  • Add the standard manifold/chart consistency assertions (as used by other pt_map dispatches in this module). Without these, a caller could pass a manifold instance that doesn’t match the charts and still get a result.
    del usys
    if len(from_chart.factors) != 2 or not all(
        isinstance(f, Cart3D) for f in from_chart.factors
    ):
        msg = (

src/coordinax/_src/charts/register_ptmap.py:1851

  • Same as above: add the standard manifold/chart consistency assertions so this dispatch rejects mismatched manifold+chart combinations early and consistently.
    del usys
    if len(to_chart.factors) != 2 or not all(
        isinstance(f, Cart3D) for f in to_chart.factors
    ):
        msg = (

docs/spec.md:1692

  • docs/spec.md still claims the only registered transition for PoincarePolar6D is the identity transform, but this PR registers pt_map transitions to/from a Cartesian phase-space product chart. Update the spec text so the authoritative spec matches the implemented behavior.
    - Transition behavior currently registered in-core:
      identity transform only (`pt_map(p, PoincarePolar6D, PoincarePolar6D) -> p`).
    - No dedicated Cartesian projection dispatch is currently defined for this chart family.

Comment on lines +1749 to +1750
Forward only: ``sqrt(|Lz|)`` discards ``sign(Lz)``, so there is no inverse.

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

Labels

📝 Add / update documentation Add or update documentation. ✅ Add / update / pass tests Add, update, or pass tests. 🐛 Fix a bug Fix a bug. ✨ Introduce new features Introduce new features.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants