Skip to content

Add binary PCK orientation kernel support#80

Merged
rhannequin merged 5 commits into
mainfrom
pck-support
Jun 22, 2026
Merged

Add binary PCK orientation kernel support#80
rhannequin merged 5 commits into
mainfrom
pck-support

Conversation

@rhannequin

@rhannequin rhannequin commented Jun 22, 2026

Copy link
Copy Markdown
Owner

Summary

Adds support for reading binary PCK (DAF/PCK) orientation kernels, a body frame's orientation over time as Euler angles.

pck = Ephem::PCK.open("moon_pa_de440_200625.bpc")
pck[31008].orientation_at(2451545.0)  # Euler angles (+ rates)
pck[31008].matrix_at(2451545.0)       # reference -> body rotation matrix

Notable

  • Generic reader: works for any binary PCK, not tied to DE440.
  • Perf: position + velocity now evaluate in a single Chebyshev pass → ~13% faster state_at / orientation_at, bit-identical results.
  • Bug fix: compute_and_differentiate with an array of times returned wrong velocities; now correct.
  • SPK output unchanged; CLI / Excerpt / Download handle .bpc too.

Fixes #76

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds first-class support for binary PCK (DAF/PCK) orientation kernels alongside existing SPK support, exposing Euler-angle orientation (+ optional rates) and a reference→body rotation matrix API, while also improving Chebyshev evaluation performance and fixing batched differentiation correctness.

Changes:

  • Introduce Ephem::PCK plus orientation segment/group types to read DAF/PCK type-2 orientation kernels and query angles_at, orientation_at, and matrix_at.
  • Refactor Chebyshev type-2 segment evaluation into shared machinery and add a fused value+derivative evaluator for improved performance.
  • Add segment grouping (SPK center/target, PCK body) to route queries across time-split segments; extend CLI/Excerpt/Download/Docs/Benchmarks and add extensive specs.

Reviewed changes

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

Show a summary per file
File Description
spec/support/test_spk_helper.rb Add binary PCK fixture path helpers for specs.
spec/ephem/spk_spec.rb Ensure SPK rejects PCK files with a helpful error.
spec/ephem/segments/segment_spec.rb Regression test for correct pairing of array times with velocities.
spec/ephem/segments/segment_group_spec.rb New tests for routing/group behavior for position + orientation groups.
spec/ephem/segments/orientation_segment_spec.rb New unit tests for OrientationSegment API and behavior.
spec/ephem/pck_spec.rb End-to-end PCK open/query/routing and accuracy vs jplephem reference.
spec/ephem/io/daf_spec.rb New tests for DAF file type detection (SPK vs PCK).
spec/ephem/download_spec.rb Add coverage for downloading NAIF .bpc kernels.
spec/ephem/core/rotation_spec.rb Add tests for rotation matrix helpers (passive convention).
spec/ephem/core/orientation_spec.rb Add tests for Orientation value object, rates, matrix composition.
spec/ephem/computation/chebyshev_polynomial_spec.rb Add tests for fused evaluate_with_derivative.
spec/ephem/cli_spec.rb Update help text expectation + add PCK excerpt/open-kernel tests.
README.md Document binary PCK orientation kernel usage and matrix application.
lib/ephem/tasks/validate_accuracy.rb Correct velocity unit label to km/day.
lib/ephem/spk.rb Reject PCK in SPK.open; use Registry + PositionGroup wrapping for split segments.
lib/ephem/segments/segment.rb Move type-2 evaluation into shared module; register SPK types via Registry.
lib/ephem/segments/segment_group.rb New base routing class for multi-segment keys (batch + scalar).
lib/ephem/segments/registry.rb Replace SPK-only registry with kind-aware registry (spk/pck).
lib/ephem/segments/position_group.rb New group wrapper routing position/state queries across segments.
lib/ephem/segments/orientation_source.rb Shared “reject position/state APIs” mixin for orientation sources.
lib/ephem/segments/orientation_segment.rb New PCK type-2 orientation segment (angles/rates/matrix).
lib/ephem/segments/orientation_group.rb New group wrapper routing orientation queries across segments.
lib/ephem/segments/chebyshev_type2.rb Shared loader/evaluator for DAF type-2 Chebyshev segments + fused eval use.
lib/ephem/segments/base_segment.rb Add start_jd/end_jd, covers?, and descriptor parsing hook for PCK.
lib/ephem/pck.rb New Ephem::PCK kernel reader, grouping by body, excerpt support.
lib/ephem/io/daf.rb Add file_type detection for SPK vs PCK (including legacy fallback).
lib/ephem/excerpt.rb Generalize excerpting to SPK or PCK and reopen matching kernel type.
lib/ephem/download.rb Add NAIF PCK download support and include .bpc in supported kernels.
lib/ephem/core/rotation.rb New kernel-agnostic rotation matrix helpers (about_*, multiply, apply).
lib/ephem/core/orientation.rb New Orientation value object with optional rates and 3-1-3 matrix composition.
lib/ephem/computation/chebyshev_polynomial.rb Add fused value+derivative evaluation for performance.
lib/ephem/cli.rb Update excerpt CLI to auto-detect SPK vs PCK and add open_kernel.
lib/ephem.rb Wire new core + segment + kernel files into the main require graph.
CHANGELOG.md Document 0.5.0 features/improvements including PCK support and perf/bug fixes.
benchmarks/run.rb Add benchmark coverage for fused evaluator and PCK orientation queries.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/ephem/cli.rb
Completes the binary PCK (DAF/PCK) orientation work on top of the draft.

- Add Core::Rotation (kernel-agnostic 3x3 helpers) and Orientation#to_matrix
  / OrientationSegment#matrix_at, centralizing the 3-1-3 (Z-X-Z),
  reference->body convention where the kernel knowledge lives.
- Route queries to the covering segment when a body/pair spans multiple
  time intervals (Position/OrientationGroup via SegmentGroup.wrap), with
  zero overhead for the common single-segment case.
- Share the compute/compute_and_differentiate rejection across orientation
  sources (Segments::OrientationSource).
- Excerpt, the excerpt CLI, and Download now handle binary PCK; kernel kind
  is auto-detected.
- Fix compute_and_differentiate returning mismatched velocities for an
  array of times; document the velocity/rate unit as km/day (rad/day).
- Tests: Orientation, Rotation, OrientationSegment, group routing, PCK,
  plus committed .bpc fixtures (2000-2030 accuracy gate + a boundary
  excerpt exercising real multi-segment routing). Validated against
  jplephem (SPK output unchanged, PCK angles exact).
State queries previously ran two full Clenshaw passes over the same
coefficients: one for position (evaluate) and one for velocity
(evaluate_derivative). Profiling showed those two passes were ~80% of
compute_and_differentiate.

Add ChebyshevPolynomial.evaluate_with_derivative, which fuses the value
and derivative recurrences into one loop so the coefficient fetch and
loop control are shared. The arithmetic of each recurrence is unchanged,
so results are bit-for-bit identical to calling the two methods
separately (verified across real and random coefficients; SPK position
and velocity still match jplephem exactly).

generate_single now uses it, speeding up every state/orientation query
(compute_and_differentiate, state_at, orientation_at): ~13% faster for
scalar state queries; the corrected batch path is now faster than it was
before the array-velocity fix.
@rhannequin rhannequin merged commit 1452eb5 into main Jun 22, 2026
57 checks passed
@rhannequin rhannequin deleted the pck-support branch June 22, 2026 21:49
@rhannequin rhannequin mentioned this pull request Jun 22, 2026
rhannequin added a commit that referenced this pull request Jun 22, 2026
## [0.5.0] - 2026-06-23

### Features

- Read binary PCK (`DAF/PCK`) orientation kernels via `Ephem::PCK`, exposing a
  body's Euler angles and rates over time (`angles_at`, `orientation_at`), the
  foundation for DE440-grade lunar libration ([#76], [#80])
- Add `Ephem::Core::Orientation` (Euler angles + optional rates) and
  `Ephem::Core::Rotation` (kernel-agnostic rotation-matrix helpers), plus
  `Orientation#to_matrix` / `OrientationSegment#matrix_at` for the built-in
  3-1-3 (Z-X-Z) reference→body convention
- Excerpt and the `excerpt` CLI now support binary PCK kernels, detecting the
  kernel kind automatically
- Download binary PCK lunar orientation kernels from NAIF via `Ephem::Download`
- Add `#inspect` and `#to_s` to `State` for easier debugging ([#67])

### Improvements

- Route queries to the covering segment when a body/pair spans multiple
  time-split segments (SPK and PCK), with no overhead for single-segment keys
- Share the type-2 Chebyshev machinery between SPK and PCK segments
- Evaluate position and velocity in a single Chebyshev pass
  (`ChebyshevPolynomial.evaluate_with_derivative`), speeding up every state /
  orientation query (`compute_and_differentiate`, `state_at`, `orientation_at`)
  with bit-for-bit identical results
- Correct the documented velocity unit to km/day (the actual, validated value)
- Remove the `numo-narray` dependency ([#65])
- Skip derivative evaluation in `Segment#compute` ([#57])
- Hoist loop-invariant `t2` computation in Chebyshev evaluation ([#58])
- Cache the `RecordParser` instance in `SummaryManager` ([#63])
- Eliminate a redundant `read_record` call in `SummaryManager` ([#62])
- Replace duplicated endianness format lookups with shared constants ([#64])
- Replace `instance_variable_get` with proper `attr_reader`s in `Excerpt`
  ([#66])
- Use separate error margins for position and velocity validation ([#61])
- Add a comprehensive benchmark suite ([#68])
- Upgrade default Ruby to 4.0.5 ([#81])
- Match SPICE last-loaded-wins precedence for overlapping segments ([#83])
- Add a dedicated spec for the shared type-2 Chebyshev evaluation ([#84])
- Bump standard from 1.50.0 to 1.55.0 by @dependabot ([#45], [#46], [#56],
  [#78])
- Bump actions/checkout from 4 to 7 by @dependabot ([#44], [#52], [#79])
- Bump rake from 13.3.0 to 13.4.2 by @dependabot ([#48], [#73])
- Bump zlib from 3.2.1 to 3.2.3 by @dependabot ([#49], [#70])
- Bump rspec from 3.13.1 to 3.13.2 by @dependabot ([#47])
- Bump parallel from 1.27.0 to 1.28.0 by @dependabot ([#71])
- Bump benchmark-ips from 2.14.0 to 2.15.1 by @dependabot ([#75])
- Bump json from 2.18.1 to 2.19.2 by @dependabot ([#77])

### Bug fixes

- Fix `compute_and_differentiate` returning mismatched velocities for an array
  of times
- Fix precision loss in `time_to_seconds` for dates far from J2000 ([#60])

[#44]: #44
[#45]: #45
[#46]: #46
[#47]: #47
[#48]: #48
[#49]: #49
[#52]: #52
[#56]: #56
[#57]: #57
[#58]: #58
[#60]: #60
[#61]: #61
[#62]: #62
[#63]: #63
[#64]: #64
[#65]: #65
[#66]: #66
[#67]: #67
[#68]: #68
[#70]: #70
[#71]: #71
[#73]: #73
[#75]: #75
[#76]: #76
[#77]: #77
[#78]: #78
[#79]: #79
[#80]: #80
[#81]: #81
[#83]: #83
[#84]: #84

**Full Changelog**: v0.4.1...v0.5.0
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.

Support binary PCK (orientation kernels) for body orientation / lunar libration

2 participants