Skip to content

kepler: validation, per-instance mu, w→argp, helpers (0.22, do not merge yet) - #168

Draft
ssmichael1 wants to merge 3 commits into
mainfrom
kepler-0.22-api
Draft

kepler: validation, per-instance mu, w→argp, helpers (0.22, do not merge yet)#168
ssmichael1 wants to merge 3 commits into
mainfrom
kepler-0.22-api

Conversation

@ssmichael1

@ssmichael1 ssmichael1 commented Aug 31, 2026

Copy link
Copy Markdown
Owner

Tracks #167. Parked until the 0.22 minor bump — do not merge. Rust API shape changes (field rename, new struct field, #[non_exhaustive] error enum).

Implements the remaining four items of the 2026-08-30 Kepler interface review (items 1–4 shipped in #146):

  • (5) ValidationKepler::try_new / Kepler::validate with kepler::Error::InvalidElement { name, value, reason }; the Python constructor and every element setter (a, eccen, inclination, raan, argp, nu, mu, deprecated w, and mean_anomaly / eccentric_anomaly) raise ValueError for a non-finite element, a <= 0, eccen ∉ [0, 1), incl ∉ [0, π], mu <= 0 (bounds strict; a failed setter leaves the set unchanged — no setter can leave NaN behind). Kepler::new stays unchecked. from_pv now raises ValueError (was RuntimeError) for open/rectilinear states and a bad mu; malformed input shape stays RuntimeError.
  • (6) muKepler.mu (m³/s², default MU_EARTH), with_mu, from_pv_with_mu; every dynamic quantity uses it. Python kepler(mu=), kepler.mu, from_pv(mu=). Pickle is 7 fields; serde defaults a missing mu to Earth's.
  • (8) wargp — Rust field renamed (only in-crate user: tle/fitting.rs). Python: argp canonical, same positional slot; w still accepted as constructor keyword and property with DeprecationWarning, kept indefinitely (no removal scheduled); both given → ValueError.
  • (9) Helpersperiapsis, apoapsis, specific_energy, angular_momentum, flight_path_angle, argument_of_latitude, true_longitude; SatState::from_kepler / satstate.from_kepler; one-line repr; PartialEq + serde on Kepler, Copy/PartialEq on Anomaly.

Docs: docs/guide/kepler.md (argp, Validation and Derived-quantities sections, per-instance μ), stubs with units on every kepler docstring, CHANGELOG (Added + Breaking-Rust lines).

Testing

  • Rust: 4 new unit tests (try_new rejection matrix incl. boundaries, MU_MOON period ratio + from_pv_with_mu round-trip, every helper against vis-viva / |r×v| / asin(r·v) identities and wrapping, serde round-trip + legacy-JSON mu default). Full suite green: 296 lib + all integration binaries (GMAT corpus included).
  • Python: 6 new tests (pickle with mu, ValueError matrix + setter atomicity, argp/w equivalence + DeprecationWarning via pytest.warns, mu dynamics, helpers, repr + satstate.from_kepler). 197 passed, 1 skipped, warning-free. The NaN-no-hang regression test became test_anomaly_setters_reject_non_finite_and_high_e_converges: non-finite mean_anomaly / eccentric_anomalyValueError with the set unchanged, eccen = 1.5 rejected, and a capped e = 0.999 solve under a watchdog thread; test_kepler_from_pv_open_or_rectilinear_is_value_error covers the exception-type change.
  • cargo clippy --all-targets -D warnings, cargo fmt, stubtest: clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PG969yapJ84DJceKt21Wen

ssmichael1 and others added 3 commits August 30, 2026 20:58
(5) Kepler::try_new / Kepler::validate reject non-finite elements,
    a <= 0, eccen outside [0, 1), incl outside [0, pi], mu <= 0 with a
    new non_exhaustive kepler::Error::InvalidElement; the Python
    constructor and the a / eccen / inclination / mu setters raise
    ValueError. Kepler::new stays unchecked.
(6) Kepler gains `mu` (default MU_EARTH; Kepler::with_mu,
    from_pv_with_mu; Python kepler(mu=), kepler.mu, from_pv(mu=)) and
    every dynamic quantity uses it. Pickle carries 7 fields; serde
    defaults a missing mu to Earth's.
(8) Kepler.w is renamed Kepler.argp (Rust: breaking field rename; the
    only in-crate user was tle/fitting.rs). Python: argp is canonical,
    w remains a constructor keyword and a property with a
    DeprecationWarning.
(9) periapsis, apoapsis, specific_energy, angular_momentum,
    flight_path_angle, argument_of_latitude, true_longitude;
    SatState::from_kepler / satstate.from_kepler; one-line kepler repr;
    PartialEq + serde on Kepler, Copy/PartialEq on Anomaly.

Docs: guide/kepler.md (argp, validation, mu, derived-quantity table),
stubs, changelog (PR link placeholder filled in a follow-up commit).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PG969yapJ84DJceKt21Wen
…ept indefinitely

Maintainer decisions on #167:
- raan / argp / nu (and the deprecated w) setters reject non-finite
  values with ValueError like the constructor; mean_anomaly /
  eccentric_anomaly stay infallible so the capped solver path remains
  exercised (regression test now feeds NaN through both and checks a
  capped e = 0.999 solve on a fresh set).
- kepler.from_pv raises ValueError (was RuntimeError) for an open or
  rectilinear state and for a bad mu; malformed input shape stays
  RuntimeError. Stub, guide and changelog breaking line updated.
- The w alias is kept indefinitely; no removal version anywhere.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PG969yapJ84DJceKt21Wen
No setter can now leave a NaN element behind: a non-finite anomaly raises
ValueError and the element set is unchanged. The solver's no-hang
guarantee is covered at the Rust level (test_mean2eccentric_nan_returns);
the Python regression test now asserts the rejection and keeps the capped
e = 0.999 solve under a watchdog thread.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PG969yapJ84DJceKt21Wen
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