empyrean.propagate

propagate(orbits, epochs, config=None, *, force_model=None, uncertainty_method=None, num_threads=None, events=None, tagged_covariance=False, thrust_arcs=None, _builtsystem=None)[source]

Propagate orbits to target epochs.

Parameters:
  • orbits (CartesianOrbits | KeplerianOrbits | CometaryOrbits | SphericalOrbits) – Input orbits with optional covariance and non-gravitational parameters.

  • epochs (Epochs) – Target epochs as an Epochs table, converted to TDB internally. Build one with Epochs.from_mjd(values, scale="tdb") (or scale="utc"); a bare array is refused, as it carries no time scale.

  • config (PropagationConfig | None) – Full propagation configuration. Construct with PropagationConfig(force_model=..., uncertainty_method=...) etc. If omitted, one is built from the sugar kwargs below (or defaults).

  • force_model (ForceModelTier | str | None) – Quick override for config.force_model. Ignored if config is given.

  • uncertainty_method (UncertaintyMethod | SigmaPoint | MonteCarlo | GaussianMixture | Auto | str | None) –

    Optional quick override for config.uncertainty_method. Accepts either an enum / string (default parameters) or a parameterized dataclass (SigmaPoint, MonteCarlo, GaussianMixture, Auto). Ignored if config is given. Pass Auto (rather than the bare AUTO enum) to tune the per-close-approach κ band edges and AGM knobs.

    All six methods run in propagate():

    • FIRST_ORDER / SECOND_ORDER / AUTO attach the STM-based state covariance (AUTO escalating to a second-order ellipsoid over close-approach windows).

    • SIGMA_POINT reconstructs a genuine sample-based state covariance (the second moment of the propagated canonical 2N+1 sigma-point set), read back tagged sigma_point.

    • MONTE_CARLO draws n_samples from the input covariance (reproducibly, for a fixed seed) and reports the Monte-Carlo impact probability on the ip_mc column of any possible-impact event. It does not reconstruct a per-epoch state covariance — the propagated states carry no state covariance under MONTE_CARLO (use SIGMA_POINT for a sampled state covariance, or compute_impact_probabilities() for the full Monte-Carlo impact-probability workflow).

    • GAUSSIAN_MIXTURE splits the input Gaussian into an adaptive mixture at close approaches; its distinctive product is the mixture-corrected impact probability. Away from encounters the output-state covariance is the linear Φ·Σ·Φᵀ mapping (like SECOND_ORDER), so for a well-determined object it reads back very close to FIRST_ORDER (tagged linear) — that is expected, not a bug.

      The mixture components themselves come back on PropagationResult.mixtures (a MixtureChains table), so a consumer can evaluate sum_k w_k * N(x | mu_k, Sigma_k) directly at a retained close-approach epoch. Four limits apply to what is retained, each a real property of the engine’s retention rather than a marshaling shortfall:

      • Depth-0 only. Only the initial split is retained; recursive AGM calls (depth > 0) are not captured.

      • Only CA epochs where AGM fired. An orbit that never triggered a split contributes no rows, not a one-component chain.

      • Component covariance is the linear map. Each component’s covariance is Phi Sigma_k Phi^T; the second-order mean correction is intentionally omitted.

      • Retained weights may sum to less than 1. A sub-Gaussian whose own sub-propagation missed the close approach (or failed to integrate) contributes no component, and the deficit is not recorded anywhere. Do not assume sum_k w_k == 1; sum weight and check.

  • num_threads (int | None) – Threads for multi-orbit propagation. None (default) and 0 both use all available cores; n > 0 pins exactly n threads. Each orbit is integrated on a single thread; parallelism is across orbits, not within a single trajectory.

  • events (EventConfig | None) – Event-detection toggles + body filter + dense-output cadence. Override individual flags here without rebuilding a full PropagationConfig. See EventConfig.

  • tagged_covariance (bool) – When True, also read back the provenance-tagged, resolved-kind covariance at every output epoch (the honest covariance that distinguishes a second-order close-approach ellipsoid from the bare linear Φ Σ₀ Φᵀ mapping on the states). The result’s tagged_covariance table is populated and tagged_covariance_series() becomes usable. Off by default — the readback recomputes the resolved kind per orbit, so it isn’t free.

  • thrust_arcs (Sequence[ThrustParams | None] | None) – Structured continuous-thrust / finite-burn input, one entry per orbit and positionally aligned with orbits (pass None for the gravity / non-grav-only orbits, or the whole argument None for a fully ballistic batch). Build each entry from ThrustParams / ThrustArc / a SteeringLaw variant. A non-empty correction_covariances triggers the burn-sensitivity propagation whose solved segments surface in the tagged-covariance thrust_segments (requires tagged_covariance=True). Length or arc/correction mismatches raise, never silently degrade.

  • _builtsystem (Any)

Return type:

PropagationResult

Returns:

PropagationResult – Propagated states, detected events, and per-orbit state sensitivity chains.

Notes

Within each orbit, states come back in ascending epoch order, always, regardless of the order the epochs were requested in. Positional pairing against an ascending, duplicate-free request grid is therefore exact; for any other request shape, join on the result’s epoch_mjd_tdb column.

The joint covariance travels in both directions. An input orbit carrying cross terms — on non_grav.non_grav_cross (the 6x3 state-Marsden border) and wide_cross (everything else) — is propagated against them rather than against its 6x6 alone, and every output row carries the propagated cross terms in the same two columns. This is what makes a chained propagation agree with the single-leg answer: the state-parameter columns are non-zero even when the input was block-diagonal, because propagation itself generates that correlation, so a second leg handed only the 6x6 reports a tighter uncertainty than the first leg supports.

Cross terms are refused without the parameter blocks they are conditioned on (the non-grav 3x3, the DT and AMRAT prior variances). Propagation passes those through unchanged rather than restating them on every output row, so when chaining legs by hand take them from the orbit that started the chain. A row with no cross terms is null, never zero — an absent correlation and a measured zero correlation are different claims.

Raises:

TypeErrorepochs is not an Epochs table.

Parameters:
  • orbits (CartesianOrbits | KeplerianOrbits | CometaryOrbits | SphericalOrbits)

  • epochs (Epochs)

  • config (PropagationConfig | None)

  • force_model (ForceModelTier | str | None)

  • uncertainty_method (UncertaintyMethod | SigmaPoint | MonteCarlo | GaussianMixture | Auto | str | None)

  • num_threads (int | None)

  • events (EventConfig | None)

  • tagged_covariance (bool)

  • thrust_arcs (Sequence[ThrustParams | None] | None)

  • _builtsystem (Any)

Return type:

PropagationResult

Examples

Defaults (Standard force model, FirstOrder uncertainty):

>>> times = Epochs.from_mjd([60500.0, 60501.0], scale="tdb")
>>> result = empyrean.propagate(orbits, times)

With a config object:

>>> cfg = PropagationConfig(
...     force_model=ForceModelTier.STANDARD,
...     uncertainty_method=SigmaPoint(),
...     num_threads=8,
... )
>>> result = empyrean.propagate(orbits, times, cfg)

With inline kwargs (sugar):

>>> result = empyrean.propagate(orbits, times, force_model="standard")