astra.propagator module

ASTRA Core Numerical Propagator — Segmented Cowell’s Method. Implements a mission-operations–grade numerical orbit propagator using Cowell’s direct integration with a Dormand-Prince DOP853 (8th-order, error-estimate 5th/3rd order) adaptive-step integrator via SciPy’s solve_ivp(method='DOP853'). Features - 6-DOF coast arcs: Two-body + J2/J3/J4 + drag + 3rd-body gravity. - 7-DOF powered arcs: Attitude-steered thrust with Tsiolkovsky-coupled mass depletion. - Segmented orchestrator: Slices propagation at engine ignition/cutoff boundaries so

the integrator never steps across a force-model discontinuity.

  • High-fidelity data: JPL DE421 Sun/Moon via Skyfield; empirical atmospheric density from F10.7 and Ap (replacing a static exponential model).

Force model includes - Two-body Keplerian gravity - J2, J3, J4 zonal harmonic perturbations (WGS84) - Empirical atmospheric drag (NRLMSISE-00 with space weather) - Solar third-body point-mass perturbation (JPL DE421) - Lunar third-body point-mass perturbation (JPL DE421) - Finite continuous thrust (7-DOF powered arcs) Numba / IEEE-754 JIT kernels use @njit(fastmath=True) (MTH-16), which allows reordering and fused operations that can differ slightly from the pure-Python _acceleration path. For validation, compare integrated trajectories or segment-level energy, not bitwise-identical acceleration samples. SRP / PHY-18 Cannonball SRP scales flux from 1 AU; uses a conical Earth umbra/penumbra geometry (planar intersection model) to continuously scale solar pressure through twilight regions — see DragConfig.srp_cylindrical_shadow (named for legacy compatibility). References - Vallado, D. A. (2013). Fundamentals of Astrodynamics and Applications. - Montenbruck & Gill (2000). Satellite Orbits. - Park et al. (2021). JPL Planetary Ephemerides DE440/DE441.

astra.propagator.srp_illumination_factor_njit(r_km, r_sun_km, earth_radius_km, sun_radius_km)[source]

Public NJIT wrapper for the dual-cone SRP illumination factor (FM-1B fix). Delegates to _srp_illumination_factor_dual_cone_njit. See that function for the full mathematical derivation (Montenbruck & Gill §3.4.2).

astra.propagator.srp_illumination_factor(r_km, r_sun_km, earth_radius_km=6378.137, sun_radius_km=695700.0)[source]

Exact dual-cone SRP illumination factor ν in [0, 1] (FM-1B fix). Computes the fractional illumination of the solar disk as seen from r_km, accounting for Earth’s occultation using exact spherical-cap intersection geometry (Montenbruck & Gill §3.4.2; Vallado 2013 Alg. 34). :param r_km: Geocentric satellite position (km), shape (3,). :param r_sun_km: Geocentric Sun position (km), shape (3,). :param earth_radius_km: Earth equatorial radius (km). :param sun_radius_km: Solar mean radius (km).

Returns:

0 = full eclipse, 1 = full sunlight, (0,1) = penumbra.

Return type:

ν ∈ [0, 1]

astra.propagator.srp_cylindrical_illumination_factor_njit(r_km, r_sun_km)[source]

Legacy cylindrical umbra model (ν=0 in-cylinder, ν=1 outside).

astra.propagator.srp_cylindrical_illumination_factor(r_km, r_sun_km)[source]

Public pure-Python legacy cylindrical umbra model.

Deprecated since version 3.7.1: The cylindrical shadow model is less accurate than the dual-cone model. Use srp_illumination_factor() instead, which applies the correct conical Earth umbra/penumbra geometry.

class astra.propagator.NumericalState(t_jd, position_km, velocity_km_s, mass_kg=None, covariance_km2=None, error_message=None)[source]

Bases: object

Full kinematic state vector at a single epoch. In 6-DOF (coast) mode, mass_kg is None and the state vector is [x, y, z, vx, vy, vz]. In 7-DOF (powered) mode, mass_kg tracks propellant depletion via Tsiolkovsky coupling: dm/dt = −F / (Isp·g₀). SE-01 Fix: frozen=True to match all other ASTRA output types (OrbitalState, FiniteBurn, ConjunctionEvent). Prevents accidental mutation of integration results. numpy array contents remain mutable by Python semantics, but field references (position_km, velocity_km_s, mass_kg) cannot be reassigned.

t_jd
position_km
velocity_km_s
mass_kg = None
covariance_km2 = None
error_message = None
class astra.propagator.DragConfig(cd=2.2, area_m2=10.0, mass_kg=1000.0, cr=1.5, include_srp=True, model='NRLMSISE00', srp_conical_shadow=True, srp_area_m2=None)[source]

Bases: object

Atmospheric drag and optional solar radiation pressure (SRP) inputs.

This dataclass is frozen (immutable) to prevent accidental mutation after construction. Create a new instance to modify parameters.

cd

Aerodynamic drag coefficient (dimensionless). Default 2.2. Typical range: 2.0–2.5 for LEO satellites.

Type:

float

area_m2

Aerodynamic drag cross-section (m²). Default 10.0.

Type:

float

mass_kg

Spacecraft mass (kg). Default 1000.0.

Type:

float

cr

Solar radiation pressure reflectivity coefficient (dimensionless). Default 1.5. Range: 1.0 (absorber) to 2.0 (perfect reflector).

Type:

float

include_srp

Enable/disable SRP force model. Default True.

Type:

bool

model

Atmospheric density model. "NRLMSISE00" (default) uses the NRLMSISE-00 empirical model with space-weather indices. "EXPONENTIAL" uses a single-layer exponential profile (faster, lower fidelity).

Type:

str

srp_conical_shadow

Use the conical (umbra/penumbra) Earth shadow model for SRP. Default True. When False, the satellite is assumed to always be in sunlight (conservative for SRP force magnitude).

Type:

bool

srp_area_m2

Optical cross-section for SRP (m²). Defaults to area_m2 when None, which is correct for compact spacecraft. Set explicitly for satellites where the solar-panel area differs significantly from the aerodynamic drag area.

Type:

float | None

cd = 2.2
area_m2 = 10.0
mass_kg = 1000.0
cr = 1.5
include_srp = True
model = 'NRLMSISE00'
srp_conical_shadow = True
srp_area_m2 = None
property srp_cylindrical_shadow

Deprecated alias for srp_conical_shadow (LOW-02). Use srp_conical_shadow.

class astra.propagator.SNCConfig(q_psd_m2_s3=1e-12, mode='white_noise')[source]

Bases: object

State Noise Compensation (Process Noise) configuration. Defines the power spectral density (PSD) of unmodeled accelerations, typically used to prevent covariance collapse in long-duration propagations.

q_psd_m2_s3 = 1e-12
mode = 'white_noise'
astra.propagator.propagate_cowell(state0, duration_s, dt_out=60.0, drag_config=None, include_third_body=True, rtol=None, atol=None, maneuvers=None, use_de=True, use_empirical_drag=True, include_stm=False, snc_config=None, coast_rtol=1e-08, coast_atol=1e-08, powered_rtol=1e-12, powered_atol=1e-12, _precomputed_sun=None, _precomputed_moon=None)[source]

Propagate an orbit using segmented Cowell’s method with DOP853. This is a mission-operations–grade numerical propagator that automatically segments the integration timeline at engine ignition/cutoff boundaries. Each segment uses the appropriate derivative function:

  • Coast segments: 6-DOF [r, v] — gravitational + drag.

  • Powered segments: 7-DOF [r, v, m] — adds thrust and Tsiolkovsky mass depletion.

The segmented approach ensures that solve_ivp never steps across a force-model discontinuity, eliminating truncation error at burn edges. Known Limitations:

  • Geopotential truncated at J6.

  • Atmospheric scale height uses single-layer exponential profile; multi-altitude molecular mass variation is a third-order effect.

  • Powered-arc default mass absolute tolerance is 10⁻⁵ kg (0.01 g), which is loose for micro-thrusters on small spacecraft; pass atol for tighter mass conservation.

  • SRP uses a dual-cone Earth umbra/penumbra shadow model (_srp_illumination_factor_dual_cone_njit). The penumbra formula is the standard Montenbruck & Gill §3.4.2 planar circle-circle intersection — industry reference for Earth-orbit SRP shadow models. Planar approximation error is O(β²/12) ≈ 1.7×10⁻⁷, below IEEE-754 double precision significance.

Parameters:
  • state0 – Initial state (position + velocity + optional mass).

  • duration_s – Total propagation duration in seconds.

  • dt_out – Output time step in seconds (default 60 s).

  • drag_config – Optional atmospheric drag parameters.

  • include_third_body – Include Sun/Moon gravity.

  • rtol – Top-level relative tolerance override (WARNING: Silently discards any fine-tuned coast_rtol and powered_rtol values).

  • atol – Top-level absolute tolerance override (WARNING: Silently discards any fine-tuned coast_atol and powered_atol values).

  • maneuvers – Optional list of FiniteBurn definitions. Burns must not overlap in time.

  • use_de – Use JPL DE421 for Sun/Moon (True) or analytical (False).

  • use_empirical_drag – Use F10.7/Ap drag model (True) or static (False).

  • coast_rtol – Relative tolerance for coast arcs (default 1e-8).

  • coast_atol – Absolute tolerance for coast arcs (default 1e-8). For high-accuracy conjunction analysis, tighten to 1e-12.

  • powered_rtol – Relative tolerance for powered arcs (default 1e-12).

  • powered_atol – Absolute tolerance for powered arcs (default 1e-12).

Returns:

List of NumericalState objects at each output time step. If maneuvers are present, each state includes the current mass.

astra.propagator.propagate_cowell_at_times(state0, times_jd, *, drag_config=None, include_third_body=True, use_de=True, maneuvers=None, include_stm=False, snc_config=None)[source]

Propagate to specific Julian Date epochs using the Cowell integrator.

Unlike propagate_cowell() which returns states at uniform dt_out intervals, this function returns states at caller-specified epochs. This is essential for:

  • Orbit determination residual computation at observation times.

  • Ephemeris generation at irregular cadences.

  • State interpolation at conjunction screening epochs.

Internally propagates with a dense output step and interpolates to the requested times using cubic spline interpolation on the propagated trajectory. The underlying force model, maneuver handling, and STM propagation are identical to propagate_cowell().

Parameters:
  • state0 – Initial state (position + velocity + optional mass/covariance).

  • times_jd – 1-D array of Julian Dates at which states are requested. Must all be ≥ state0.t_jd. Need not be sorted (output will match the input order).

  • drag_config – Optional atmospheric drag parameters.

  • include_third_body – Include Sun/Moon gravity (default True).

  • use_de – Use JPL DE421 ephemeris for Sun/Moon (default True).

  • maneuvers – Optional list of FiniteBurn objects.

  • include_stm – Propagate State Transition Matrix for covariance.

  • snc_config – Process noise configuration.

Returns:

List of NumericalState objects, one per requested epoch, in the same order as times_jd.

Raises:

ValueError – If times_jd is empty or contains epochs before state0.t_jd.

Example:

import astra
import numpy as np
state0 = astra.NumericalState(
    t_jd=2460000.5,
    position_km=np.array([6778.0, 0.0, 0.0]),
    velocity_km_s=np.array([0.0, 7.668, 0.0]),
)
obs_times = np.array([2460000.51, 2460000.52, 2460000.55])
states = astra.propagate_cowell_at_times(state0, obs_times)
for s in states:
    print(f"t={s.t_jd:.5f}  r={s.position_km}")
astra.propagator.propagate_cowell_batch(states, duration_s, dt_out=60.0, drag_config=None, maneuvers=None, include_third_body=True, include_stm=False, max_workers=None, use_empirical_drag=True)[source]

Propagate multiple satellites concurrently with the high-fidelity Cowell integrator. This is a production batch wrapper around propagate_cowell() that parallelises propagation over N initial states using a ThreadPoolExecutor. It eliminates the ad-hoc ThreadPoolExecutor pattern that users had to replicate (and which already existed inline inside find_conjunctions()). The input uses dict[str, NumericalState] (satellite-ID → state) rather than a list, which is consistent with the TrajectoryMap convention used throughout ASTRA (e.g. find_conjunctions). This also makes the key explicit and avoids any ambiguity when the caller needs to correlate inputs and outputs. :param states: dict[satellite_id, NumericalState] — one entry per satellite.

The key (string) is used as the map key in the returned dict.

Parameters:
  • duration_s – Total propagation duration in seconds (identical for all).

  • dt_out – Output step size in seconds (default 60 s).

  • drag_config – Optional DragConfig; applied uniformly to all satellites unless overridden per-satellite in the future.

  • maneuvers – Optional dict[satellite_id, list[FiniteBurn]]. Missing keys default to an empty burn sequence.

  • include_third_body – Enable Sun/Moon third-body gravity.

  • include_stm – Whether to propagate the 6x6 State Transition Matrix.

  • max_workers – Thread pool size. Defaults to min(32, len(states)).

  • use_empirical_drag – Whether to use empirical (F10.7/Ap) drag calculations.

Note

Atmosphere model (NRLMSISE-00 or exponential) and SRP are controlled via the drag_config argument. Set DragConfig(model='NRLMSISE00', include_srp=True) to enable high-fidelity atmosphere and SRP; these are NOT separate kwargs. Returns: dict[satellite_id, list[NumericalState]] — propagated state histories. Satellites that fail propagation are absent from the dict; their error is logged at WARNING level.

Raises:

ValueError – If states is empty or duration_s <= 0.

Example::

import astra, numpy as np s1 = astra.NumericalState(t_jd=2460000.5,

position_km=np.array([6778.0, 0.0, 0.0]), velocity_km_s=np.array([0.0, 7.668, 0.0]))

s2 = astra.NumericalState(t_jd=2460000.5,

position_km=np.array([6788.0, 0.0, 0.0]), velocity_km_s=np.array([0.0, 7.658, 0.0]))

results = astra.propagate_cowell_batch(

{“ISS”: s1, “DEBRIS-A”: s2}, duration_s=3600.0

) for sat_id, traj in results.items():

print(sat_id, len(traj), “steps”)