Skip to main content

Uncertainty-first orbit propagation, ephemeris, orbit determination, and event detection for asteroids and comets, powered by automatic differentiation

Project description

empyrean

empyrean

Uncertainty-first orbit propagation, ephemeris, orbit determination, and event detection for asteroids and comets, powered by automatic differentiation

CI PyPI Python versions Source license Binary license
Built with Claude Code Website GitHub


pip install empyrean

A plain install pulls empyrean together with the B612 Foundation's pre-packaged SPICE kernels (~640 MB). After installation, the first call to empyrean.initialize() downloads a small remainder (moon_pa, EGM2008, jwst_rec — about 370 MB) that isn't available on PyPI.

What it does

  • Propagation — N-body (Sun, planets, Moon, Pluto) with EIH general relativity, Sun J2 and Earth J2–J4 zonal harmonics, 16 asteroid perturbers, and the Marsden non-gravitational model — selectable across Approximate / Basic / Standard force-model tiers (Standard is the default). GR15 and DOP853 integrators.
  • Uncertainty — First-order (Jet1) state transition matrices; second-order (Jet2) state transition tensors.
  • Ephemeris — RA/Dec, rates, photometry (H–G, H–G₁G₂, H–G₁₂), light time, phase angle, solar elongation, local horizon.
  • Orbit determination — Gauss, Herget, and systematic-ranging (admissible region + Manifold of Variations) IOD → N-body differential correction with STM caching and outlier rejection. Validated against find_orb and JPL SBDB.
  • Events — Close approach (start/end), periapsis, gravitational capture (start/end), shadow entry/exit, atmospheric entry/exit, impact, and possible impact.

Quick start

import empyrean
from empyrean import Epochs, TimeScale

empyrean.download_data()   # SPICE kernels, first run only
empyrean.initialize()

# Query SBDB for Apophis and propagate through its 2029 Earth flyby
orbits = empyrean.query_sbdb(["Apophis"])
epochs = Epochs.from_kwargs(mjd=[65000.0], scale=TimeScale.TDB)
result = empyrean.propagate(orbits, epochs)

# Event timeline
for i in range(len(result.events.summary)):
    ev = result.events.summary
    print(f"{ev.event_type.to_pylist()[i]:25s} "
          f"{ev.body.to_pylist()[i]:8s} "
          f"MJD {ev.epoch.to_numpy()[i]:.2f}")

Orbit determination

obs, radar = empyrean.read_ades("observations.psv")   # (optical, radar)
result = empyrean.determine(obs)                       # one fit per call
print(
    f"converged={result.converged}, "
    f"RMS={result.summary.rms_ra_arcsec:.2f}\" RA / "
    f"{result.summary.rms_dec_arcsec:.2f}\" Dec"
)

Ephemeris

observers = empyrean.get_observer_states(["W84", "F51"], epochs)
eph = empyrean.generate_ephemeris(orbits, observers)

print(eph.ephemeris.coordinates.lon.to_numpy())   # RA (degrees)
print(eph.ephemeris.coordinates.lat.to_numpy())   # Dec (degrees)
print(eph.ephemeris.mag.to_numpy())               # apparent V magnitude

Uncertainty

from empyrean import UncertaintyMethod

# Second-order: populates STM (6x6) and STT (6x6x6)
result = empyrean.propagate(
    orbits, epochs,
    uncertainty_method=UncertaintyMethod.SECOND_ORDER,
)
print(result.sensitivity.stms_array().shape)   # (N, 6, 6)
print(result.sensitivity.stts_array().shape)   # (N, 6, 6, 6)

Impact probability and B-plane geometry

For each detected close approach, you can ask the propagator for an impact-probability assessment or a full B-plane breakdown — and run several uncertainty methods side-by-side on the same encounter:

from empyrean import UncertaintyMethod

ips = empyrean.compute_impact_probabilities(
    orbits,
    end_epoch=63000.0,
    methods=[UncertaintyMethod.FIRST_ORDER, UncertaintyMethod.SECOND_ORDER],
)
ips.epochs.scale                    # "tdb"
ips.where(ips.method == "second_order").ip_second_order.to_numpy()
ips.ip_linear.to_numpy()            # always populated

bps = empyrean.compute_b_planes(orbits, 63000.0, [UncertaintyMethod.SECOND_ORDER])
print(bps.b_dot_t_km.to_numpy())    # B·T (km)
print(bps.b_dot_r_km.to_numpy())    # B·R (km)
print(bps.semi_major_3sig_km.to_numpy())  # 3σ ellipse semi-major

Returns typed ImpactProbabilities and BPlanes quivr tables — one row per (method × orbit × body) encounter, with the closest-approach time as an embedded Epochs sub-table so .to_utc() / .to_tdb() just works.

Data files

empyrean needs a set of SPICE kernels. Most arrive via PyPI as installation dependencies; the remainder download on first use.

From pip (installed automatically with empyrean)

Package File Size
naif-de440 de440.bsp 114 MB
jpl-small-bodies-de441-n16 sb441-n16.bsp 616 MB
naif-eop-high-prec earth_latest_high_prec.bpc 5 MB
naif-eop-historical earth_620120_*.bpc 5 MB
naif-eop-predict earth_*_predict.bpc 1 MB
mpc-obscodes obscodes_extended.json 266 KB

empyrean bundles gm_de440.tpc (12 KB) in the wheel itself. On initialize(), empyrean stages a symlinked cache at ~/.empyrean/b612-cache/ mapping these paths into the filenames villeneuve expects.

Downloaded on first initialize()

File Size Source
moon_pa_de440_200625.bpc 12 MB NAIF — Moon orientation
jwst_rec.bsp 121 MB NAIF — JWST ephemeris (for JWST observations)

Any of these can be relocated with EMPYREAN_DATA_DIR, and individual files can be preset with VILLENEUVE_*_PATH environment variables.

Accuracy

Validated against JPL Horizons, ASSIST (reboundx), and find_orb on 43 objects across 13 dynamical populations (NEOs, MBAs, Trojans, TNOs, comets, etc.). Sub-meter propagation accuracy on bounded timescales. See the validation report.

No guarantee of accuracy

empyrean performs numerical computations used in planetary-science and mission-planning contexts. Outputs should not be used as the sole basis for any decision — including but not limited to impact monitoring, mission planning, collision avoidance, or navigation — without independent verification. See the LICENSE file shipped with this package for the full terms.

License

empyrean is dual-licensed:

  • Wrapper / binding source code — the Rust API surface, C-ABI bindings, and Python wrapper sources in the main repository — is licensed under the BSD 3-Clause License.
  • This Python wheel (and any other pre-compiled binary distribution of empyrean) is licensed under the proprietary Empyrean Binary License. The wheel is free to install and use (including commercial use) but may not be redistributed, modified, reverse-engineered, decompiled, or disassembled.

The BSD-3 grant covers only the binding / integration layers in the public repository. The propagation engine, orbit- determination engine, and automatic-differentiation library are proprietary closed-source components distributed only inside the compiled wheel — the wrapper sources call into them through stable internal APIs but do not contain their implementations. Cloning the repository will not let you build a working empyrean from source; install the published wheel.

Copyright © 2024–2026 Joachim Moeyens. All rights reserved.

Links

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

empyrean-0.7.0rc1-cp312-cp312-manylinux_2_34_x86_64.whl (7.1 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.34+ x86-64

empyrean-0.7.0rc1-cp312-cp312-macosx_11_0_arm64.whl (6.5 MB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

File details

Details for the file empyrean-0.7.0rc1-cp312-cp312-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for empyrean-0.7.0rc1-cp312-cp312-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 834f45cae26da394496668bde8db8f41299763fb9811ee03d6fa302534294a41
MD5 ad77f4c9ebad46daeb07beaee317e627
BLAKE2b-256 c8c6558d976936649434f1e98bc33a09e610b842920efaad7dab2a0a4d1f1241

See more details on using hashes here.

Provenance

The following attestation bundles were made for empyrean-0.7.0rc1-cp312-cp312-manylinux_2_34_x86_64.whl:

Publisher: release.yml on Empyrean-Dynamics/empyrean

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file empyrean-0.7.0rc1-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for empyrean-0.7.0rc1-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 f3635b6e94912d6b742c4a482b725719db7296a366f25e15ee63b40bde01e153
MD5 6829c17d81b410c1f9185909b5c8dec5
BLAKE2b-256 02bda7fabce87eb0e3e146cbd8d7cfa5a889f2dbc00f065bb73b8ce228ad4890

See more details on using hashes here.

Provenance

The following attestation bundles were made for empyrean-0.7.0rc1-cp312-cp312-macosx_11_0_arm64.whl:

Publisher: release.yml on Empyrean-Dynamics/empyrean

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page