A fast, safe, and modular Rust library for orbit determination of Solar System small bodies. Outfit focuses exclusively on orbital dynamics and computation: Gauss IOD, differential orbit correction, ephemeris generation, Keplerian propagation, reference frame transformations, and JPL ephemeris support. Observation I/O and data structures are provided by the companion crate photom.
Ecosystem split
Outfit v3 is a focused orbital dynamics engine. Everything related to observation loading (MPC 80-column, ADES XML, Parquet), observer management, and astrometric data structures now lives in the separate photom crate. Outfit depends onphotomand exposes theFitIODtrait that bridges photom'sObsDatasetinto the orbit fitting pipeline.
Table of Contents
- Features
- Ecosystem: Outfit + photom
- Installation
- Quick Start
- Initial Orbit Determination
- Differential Orbit Correction
- Uncertainty Propagation
- Ephemeris Generation
- Cargo Feature Flags
- Performance & Reproducibility
- Roadmap
- Contributing
- License
- Acknowledgements
Features
- Initial Orbit Determination (IOD)
- Gauss method on observation triplets
- Iterative velocity correction with Lagrange coefficients
- Dynamic acceptability filters (perihelion, eccentricity, geometry)
- RMS evaluation on extended arcs
- Differential Orbit Correction
- Iterative Newton–Raphson least-squares refinement of equinoctial elements
- Projection-based outlier rejection loop (chi-squared per observation)
- Covariance matrix estimation with posterior uncertainty rescaling
- Configurable free/fixed element mask (useful for short arcs)
- Stagnation and divergence detection with typed error variants
FitLSQtrait: per-trajectory pipeline (IOD seed → differential correction) on anyObsDataset
- Ephemeris generation
- Predict apparent sky positions
(RA, Dec)and distances from anyOrbitalElements - Compute geometric quantities: phase angle, solar elongation, radial velocity, apparent angular rates
- Combined mode computes position and geometry in a single propagation
- Three generation modes per observer:
Single,Range(uniform grid),At(arbitrary epoch list) - Multiple observers in one typed
EphemerisRequest; per-epoch errors collected without aborting the batch - Choice of two-body (Keplerian) or N-body (DOP853) propagator; first- or second-order aberration correction
- Predict apparent sky positions
- Orbital elements
- Classical Keplerian elements
- Equinoctial elements with conversions and two-body solver
- Cometary elements
- JPL ephemerides
- Interface with JPL DE440 (Horizons and NAIF/SPICE formats)
- Reference frames & preprocessing
- Precession, nutation (IAU 1980), aberration, light-time correction
- Ecliptic ↔ equatorial conversions, RA/DEC parsing, time systems
- Observer geometry
- Geocentric and heliocentric observer positions in AU, J2000
- Batch processing
- Single-trajectory and full-dataset IOD via the
FitIODtrait - Full least-squares fitting for all trajectories via the
FitLSQtrait - Optional parallel batch execution with Rayon (
parallelfeature)
- Single-trajectory and full-dataset IOD via the
Ecosystem: Outfit + photom
Outfit is one half of a two-crate pipeline:
| Crate | Responsibility |
|---|---|
| photom | Observation I/O (MPC 80-col, ADES XML, Parquet), data structures (ObsDataset, Observer, error models), trajectory grouping |
| outfit | Pure orbital computation: Gauss IOD, differential correction, ephemeris generation, Keplerian/equinoctial elements, JPL ephemerides, reference frames, residuals |
A typical workflow:
- Use photom to load observations into an
ObsDataset. - Call outfit's
FitIOD::fit_iod/FitIOD::fit_full_iodfor initial orbit determination, orFitLSQ::fit_lsqfor a full least-squares fit. - Inspect the returned
GaussResult/DifferentialCorrectionOutputand RMS values. - Optionally, call
OrbitalElements::computewith anEphemerisRequestto generate predicted positions.
Installation
Add Outfit and photom to your Cargo.toml:
[]
= "3.0.0"
= { = "0.1.0", = ["mpc_80_col"] }
Enable optional features as needed:
[]
= "3.0.0"
= { = "0.1.0", = ["mpc_80_col", "ades", "polars"] }
Quick Start
Single-trajectory IOD from an MPC 80-column file
use ObsDataset;
use ObsErrorModel;
use Ut1Provider;
use ;
use FitIOD;
use ;
use IODParams;
Batch IOD — all trajectories at once
use ObsDataset;
use ObsErrorModel;
use Ut1Provider;
use ;
use ;
use ;
use IODParams;
Initial Orbit Determination
Outfit implements the Gauss method on observation triplets:
- Select candidate triplets
(i, j, k)with spacing/quality heuristics. - Solve for topocentric distances and the heliocentric state at the central epoch.
- Apply dynamic acceptability filters (perihelion, eccentricity, geometry).
- Refine velocity with Lagrange coefficients (iterative correction loop).
- Evaluate RMS of normalized astrometric residuals on an extended arc to rank solutions.
Designed for robustness and speed in survey-scale use (LSST, ZTF, ...).
Differential Orbit Correction
Starting from an initial orbit (e.g. from the Gauss IOD step), outfit can refine the solution via weighted least-squares differential correction:
- Compute predicted
(RA, Dec)for each observation using the current elements. - Form the design matrix of partial derivatives of the predicted coordinates with respect to the six equinoctial elements.
- Solve the normal equations to obtain the element correction vector δx.
- Apply the correction, check convergence (
‖δx‖ < threshold), and iterate (Newton–Raphson). - After convergence, apply projection-based outlier rejection: observations whose chi-squared contribution exceeds the configured threshold are flagged and the inner loop is re-run on the reduced set. Iterate until the selection is stable.
- Rescale the covariance matrix by the posterior normalised RMS.
The FitLSQ trait exposes this pipeline at the dataset level:
use ObsDataset;
use ObsErrorModel;
use Ut1Provider;
use ;
use ;
use ;
use IODParams;
Uncertainty Propagation
Outfit tracks orbital uncertainties throughout the full pipeline — from the least-squares fit through to element representation conversions.
Generation from differential correction
The covariance matrix is produced directly by the FitLSQ pipeline. At the end of each Newton–Raphson convergence, solve_weighted_least_squares builds the normal matrix G⊤WG and inverts it (Cholesky, with QR fallback) to obtain the 6×6 covariance matrix Γ = (G⊤WG)⁻¹ in equinoctial element space:
Γ[j,k] = (G⊤WG)⁻¹[j,k] (6×6, equinoctial basis)
This raw covariance is then rescaled by a posterior inflation factor μ that accounts for the degrees of freedom and the quality of the fit:
- if normalised RMS ≤ 1 (good fit): μ = √(n_measurements / (n_measurements − n_free))
- if normalised RMS > 1 (poor fit): μ = normalised_rms × √(n_measurements / (n_measurements − n_free))
The final covariance is stored in DifferentialCorrectionOutput::uncertainty and embedded in the returned OrbitalElements::Equinoctial variant.
Propagation between element representations
Each OrbitalElements variant carries an optional covariance: Option<OrbitalCovariance> and an optional uncertainty: Option<*Uncertainty> (per-element 1-σ standard deviations). When converting between representations, the covariance is propagated via first-order linear (Jacobian) propagation:
Σ_y = J · Σ_x · Jᵀ
where J = ∂y/∂x is the 6×6 Jacobian of the transformation evaluated at the nominal elements. The following Jacobians are computed analytically:
| Conversion | Jacobian |
|---|---|
| Keplerian → Equinoctial | ∂(a,h,k,p,q,λ) / ∂(a,e,i,Ω,ω,M) |
| Equinoctial → Keplerian | ∂(a,e,i,Ω,ω,M) / ∂(a,h,k,p,q,λ) |
| Cometary → Keplerian | ∂(a,e,i,Ω,ω,M) / ∂(q,e,i,Ω,ω,ν) |
| Cometary → Equinoctial | chain rule via Keplerian |
Conversions near singularities (e → 0 for Keplerian, i → 0 for equatorial) set undefined partial derivatives to zero; equinoctial elements are preferred for nearly circular or equatorial orbits to avoid these singular regions.
use ;
use ;
use Matrix6;
// Keplerian elements with a diagonal covariance (simplified example).
let cov = OrbitalCovariance ;
let oe = Keplerian ;
// Convert to equinoctial — covariance is automatically propagated via Jacobian.
let oe_eq = oe.to_equinoctial.unwrap;
if let Equinoctial = oe_eq
Ephemeris Generation
Given any OrbitalElements, outfit can predict the apparent sky position and geometric state of the body as seen from one or more observers:
use ;
use ;
// `elements` obtained from IOD or differential correction.
let result = elements.compute;
for entry in result.successes
The pipeline converts elements to equinoctial form, propagates with the selected propagator (two-body or N-body), rotates from ecliptic to equatorial J2000, and applies aberration correction. Errors at individual epochs are stored in the result rather than aborting the computation.
Performance & Reproducibility
- Deterministic runs by default (set RNG seeds explicitly when noise is used).
- Precompute observer positions to avoid ephemeris I/O in hot paths.
- Compile with
--releasefor production. - Keep ephemerides cached locally to avoid I/O stalls on repeated runs.
- For large trajectory sets, tune
IODParams.batch_size(withparallel) so each batch fits comfortably in cache (start with 4–8 and benchmark). - Handle errors explicitly: a non-finite RMS surfaces as
OutfitError::NonFiniteScore.
Documentation
To compile the documentation locally, run the following command in the terminal:
RUSTDOCFLAGS="--html-in-header /katex-header.html"
Roadmap
- Hyperbolic & parabolic orbits (e ≥ 1) for interstellar candidates
- Vaisälä method for short arcs
- Additional ephemerides backends (e.g., ANISE/SPICE integration)
See the issue tracker for details and discussion.
Contributing
Contributions are welcome!
Please open an issue to discuss substantial changes. For PRs, please:
- Add tests for new functionality
- Keep public APIs documented
- Ensure
cargo fmtandcargo clippypass (-D warningsrecommended) - Include benchmarks when touching hot paths
A typical dev loop:
License
This project is licensed under the CeCILL-C Free Software License Agreement. See the LICENSE file.
Acknowledgements
- The OrbFit project and its authors for foundational algorithms and references.
- The maintainers of JPL ephemerides and the broader open-source ecosystem (linear algebra, I/O, benchmarking crates) that Outfit builds upon.