Changelog¶
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog. Brahe's versioning and deprecation policy is modeled on NumPy's policy rather than strict SemVer — see the versioning documentation for the full policy, including the transitional deprecation window currently in effect.
Each release groups entries under the Keep a Changelog section headings in the order Added, Changed, Deprecated, Removed, Fixed. Entries in Deprecated correspond to APIs that still work in this release but emit a DeprecationWarning or FutureWarning; entries in Removed list APIs that previous releases had deprecated.
[1.7.0] - 2026-07-21¶
Added¶
- Native SPICE kernel support:
SPKandBPCKreaders (DAF container, SPK Type 2/3, binary PCK Type 2), usable standalone or via the global registry. @duncaneddy (#376) - Global multi-kernel registry:
load_kernel,unload_kernel,clear_kernels,loaded_kernels; kernels stay resident simultaneously with most-recently-loaded precedence and epoch-aware chain fallback. @duncaneddy (#376) NAIFIdenum (planets, planetary-system barycenters, major moons,Id(i32)catch-all) andFrameIdenum (MoonPaDe440= 31008 +Id(i32)); all query functions takeimpl Into<NAIFId>/impl Into<FrameId>, so raw integer IDs keep working. Python mirrors asNAIFId/FrameIdIntEnums. @duncaneddy (#376)SPICEKernelenum covering every downloadable kernel — DE (de430–de442s), JPL satellite ephemeris kernels (mar099,mar099s,jup365,sat441,ura184,nep097,plu060), and binary PCK (moon_pa_de440) — plusKernelSourcefor bring-your-own kernel paths. @duncaneddy (#376)load_common_kernels()(de440s + moon_pa_de440, ~46 MB) andload_all_kernels()(~2.5 GB) pre-initialization helpers. @duncaneddy (#376)- Generic NAIF-ID ephemeris queries:
spk_position,spk_velocity,spk_state(pooled, cross-kernel chaining) and kernel-scopedspk_position_from_kernel/spk_velocity_from_kernel/spk_state_from_kernel. @duncaneddy (#376) - Per-body kernel-backed accessors
{body}_{position,velocity,state}_spicefor Sun, Moon, Mercury, Venus, Mars, Jupiter, Saturn, Uranus, Neptune, and the SSB. The five outer planets return true body centers via a two-leg DE + satellite-ephemeris-kernel sum (kernel auto-downloaded on first use: mar099s ~68 MB, jup365 ~1.1 GB, sat441 ~662 MB, ura184 ~387 MB, nep097 ~105 MB);{planet}_barycenter_{position,velocity,state}_spicevariants provide the planetary-system barycenter from the DE kernel alone. @duncaneddy (#376) - PCK orientation queries with typed attitude returns:
pck_euler_angle(EulerAngle, ZXZ),pck_euler_angle_and_rates,pck_euler_rates,pck_quaternion(Quaternion),pck_rotation_matrix(RotationMatrix), plus the rawpck_euler_angles. @duncaneddy (#376) Epoch::spice_et()— SPICE ephemeris time (TDB seconds past J2000) convenience accessor;Epoch::seconds_past_j2000_as_time_systemfor other time systems. @duncaneddy (#376)datasets::naif::download_spice_kernelfor any known NAIF kernel (DE, satellite ephemeris, binary PCK), exposed in Python asdatasets.naif.download_spice_kernel. @duncaneddy (#376)- ANISE validation suite (mm-level matched-ET comparisons, network-gated lunar DCM validation) and native-vs-ANISE criterion benchmarks. @duncaneddy (#376)
- Learn/API documentation for the spice module and four standalone examples, enabled in CI with cached kernels. @duncaneddy (#376)
- Lunar reference frames
LCI/LFPA/LFMEand Mars framesMCI/MCMFwith{rotation|position|state}_{from}_to_{to}transformations, cross-centerstate_eci_to_lci/state_eci_to_mci, and automaticmoon_pa_de440PCK loading. @duncaneddy (#377) - Native IAU/WGCCRE 2015 body-rotation engine (
rotation_icrf_to_body_fixed_iau,iau_rotation_model_ids) with an embedded 17-body coefficient table transcribed frompck00011.tpcand validated against ANISE. @duncaneddy (#377) - Centralized
ReferenceFrameenum and frame router (rotation_frame_to_frame,position_frame_to_frame,state_frame_to_frame) with generic NAIF-ID variants (BodyCenteredICRF,BodyFixedIAU,BodyFixedPCK) and"ECI"/"ECEF"string aliases. @duncaneddy (#377) CentralBodyabstraction (Earth, Moon, Mars, EMB, SSB, Custom) withfrom_naif_id(), andForceModelConfig::for_body(),lunar_default()(GRGM660PRIM 50×50, Earth+Sun third bodies, Moon+Earth occultation),mars_default()(GMM-2B 50×50, exponential drag, Mars occultation), andcislunar_default()(EMB-centered) constructors. @duncaneddy (#377)- Barycentric (EMB/SSB) propagation with correct direct/differential third-body handling;
ThirdBodygainsEarth,Phobos,Deimos, andCustom { name, naif_id, gm }variants. @duncaneddy (#377) - Multi-body eclipse modeling via
occulting_bodieson the SRP configuration and newOccultingBodytype. @duncaneddy (#377) - Body-generic dynamics functions:
accel_third_body_for_body,eclipse_conical_for_body,eclipse_cylindrical_for_body,accel_relativity_for_body,accel_drag_for_body,state_eci_to_koe_for_body. @duncaneddy (#377) state_bci,state_bcbf, andstate_in_frame(frame, epoch)on the orbit state-provider traits (DOrbitStateProvider/SOrbitStateProvider), implemented on the numerical, Keplerian, and SGP propagators and both trajectory types. @duncaneddy (#377)OrbitFrame::BodyCenteredInertial(center): non-Earth propagator trajectories carry their center's NAIF ID, and trajectory Earth-frame conversions (point queries, batchto_*, covariance, CCSDS OEM export) re-center through the frame router;state_koe_oscreturns elements about the trajectory's own center using that body's GM. @duncaneddy (#377)- User-defined body-fixed frames:
register_custom_frame(key, rotation, omega=None)+ReferenceFrame::BodyFixedCustom{center, key}(epoch->DCM callback with optional angular-velocity callback; numeric transport-term fallback), with a runnable example. @duncaneddy (#377) state_koe_to_eci_for_body(inverse ofstate_eci_to_koe_for_body),ReferenceFrame::ECI/ECEFaliases,kernel_is_loaded(), and theSECONDS_PER_JULIAN_CENTURYconstant. @duncaneddy (#377)just setuprecipe for local development (uv venv, pre-commit hooks, and pre-downloading the de440s/moon_pa_de440/mar099s kernels tests expect cached). @duncaneddy (#377)- NAIF
mar099sMars satellite kernel support (download_satellite_kernel,load_kernel("mar099s")) for Phobos/Deimos ephemerides. @duncaneddy (#377) - Physical constants
R_MARS,OMEGA_MARS,OMEGA_MOON,GM_PHOBOS,GM_DEIMOS. @duncaneddy (#377) ForceModelConfig::validate()with clear errors for invalid central-body/force-model combinations, called automatically at propagator construction. @duncaneddy (#377)- Python bindings for all of the above (
ReferenceFrame,CentralBody,OccultingBody, extendedThirdBody, config constructors, frame functions,state_in_frame). @duncaneddy (#377) - CI caching of kernel and gravity-model downloads across jobs and workflow runs, with a weekly keep-warm workflow. @duncaneddy (#377)
- Learn/API documentation pages and runnable lunar/Mars propagation examples (Python + Rust). @duncaneddy (#377)
- Clenshaw-summation spherical-harmonic gravity kernel (
GravityModel::compute_spherical_harmonics_clenshaw,accel_gravity_spherical_harmonics_clenshaw), with serial and parallel (order-parallel, bitwise-identical) execution — Rust + Python. @duncaneddy (#378) GravityModelCoefficientsload configuration (Clenshawdefault /Cunningham/Both) withfrom_model_type_with_coefficients/from_file_with_coefficientsconstructors (Rust + Python) andload_uncached_with_coefficients(Rust only, matchingload_uncached), plusprecompute_*/drop_*/has_*coefficient-set lifecycle methods — Rust + Python. @duncaneddy (#378)GravityModel::get_c(n, m)/get_s(n, m)single-coefficient accessors — Rust + Python. @duncaneddy (#378)accel_gravity_spherical_harmonics_cunninghamconvenience function — Rust + Python. @duncaneddy (#378)- High-precision reference tests: Clenshaw kernel pinned against independent 40-digit mpmath evaluations of EGM2008_360 to 1e-13 relative at degrees 120–200, with the generator committed as
scripts/generate_clenshaw_gravity_reference.py. @duncaneddy (#378) - The Cunningham kernel returns a descriptive error (instead of silent NaN) on denormalized-recursion overflow. @duncaneddy (#378)
set_global_gravity_modelPython binding (mirrors the existing Rust function). @duncaneddy (#378)- Clenshaw-vs-Cunningham benchmark suite in
benchmarks/gravity_benchmarks.rs. @duncaneddy (#378) is_empty()method onStaticEOPProvider,FileEOPProvider, andCachingEOPProvider(Python bindings), satisfying clippy'slen_without_is_emptyfor the newly workspace-coveredbrahe-pycrate. @duncaneddy (#380)- Solid Earth tide accelerations for numerical propagation per IERS Conventions (2010) TN36 §6.2.1: frequency-independent lunisolar corrections to degree-2/3 geopotential coefficients with degree-4 coupling (Eqs. 6.6–6.7, anelastic Love numbers from Table 6.3), and optional frequency-dependent corrections from Tables 6.5a/b/c via
SolidTideConfig(frequency_dependent=True). @duncaneddy (#385) TidesConfigurationandPermanentTideConfig(Auto/ConvertTo(system)/Off) onForceModelConfig.tidesto enable tidal corrections and control permanent-tide normalization of the static field's C̄20 (IERS TN36 §6.2.2); tides remain disabled by default in all force-model presets. @duncaneddy (#385)GravityModel.convert_tide_system(Rust and Python) to convert a gravity model's C̄20 between mean-tide, zero-tide, and conventional tide-free systems. @duncaneddy (#385)- Rust API
accel_solid_earth_tides/solid_earth_tide_coefficientsinorbit_dynamics::tidesfor direct evaluation of tide accelerations and coefficient corrections. @duncaneddy (#385) - Warnings for tide configurations that double-count the permanent tide (zero-tide/mean-tide conversion combined with solid tides, or shared global gravity models): Rust warning at propagator construction, suppressible
UserWarningin Python. @duncaneddy (#385) - Learn documentation page on tidal corrections (tide systems, permanent tide handling, solid Earth tides) and runnable Python/Rust examples:
force_model_tides,tides_permanent_only,tides_static,tides_static_time_varying. @duncaneddy (#385) ReferenceFrame.EMR,ReferenceFrame.SER, andReferenceFrame.GSEsynodic frames (NASA TP-20220014814) supported across the frame router (rotation/position/state_frame_to_frame,state_in_frame), with exact rotation-matrix time derivatives (GTDS/STK convention) for the velocity transform. @duncaneddy (#393)- Pairwise synodic transforms
rotation/position/state_gcrf_to_{emr,ser,gse}and inverses in Rust and Python. @duncaneddy (#393) - Native SPK acceleration evaluation via analytic Chebyshev differentiation:
spk_accelerationandspk_acceleration_from_kernel(Rust and Python). @duncaneddy (#393) SUN_EARTH_BARYCENTER_IDsynthetic frame-center ID with GM-weighted Sun-Earth barycenter resolution in the router's translation seam. @duncaneddy (#393)- Batch state-provider methods
states_bci,states_bcbf, andstates_in_frameonSOrbitStateProvider/DOrbitStateProviderand on theSGPPropagator,KeplerianPropagator, andNumericalOrbitPropagatorPython classes. @duncaneddy (#393) - Documentation: Synodic Reference Frames Learn page and Library API page, frame/kernel-requirement table entries, and SPK acceleration API docs. @duncaneddy (#393)
- Per-body third-body configuration:
ThirdBodyConfigurationpairs each perturber with its ownephemeris_sourceandgravitymodel;SphericalHarmonicandEarthZonalfields are evaluated at the object's position relative to the perturbing body in that body's fixed frame, with a point-mass indirect term. @duncaneddy (#394) - Public
accel_third_body_field_for_body(Rust + Python) evaluating a configured gravity model (point-mass, spherical-harmonic, or Earth-zonal) for a perturbing body about any central body. @duncaneddy (#394) ThirdBodyplanetary-system barycenter variantsMarsBarycenter–NeptuneBarycenter(NAIF 4–8, system GMs), used by the default Earth force models;accel_third_bodyaccepts both barycenter and planet-center variants (the latter auto-load their satellite-system kernels). @duncaneddy (#394)DragConfiguration.bodyto attribute drag to a non-central body: density and relative wind are evaluated at the object's state relative to that body (enables Earth drag on EMB-centered propagations). @duncaneddy (#394)GravityConfiguration::Zero— explicit no-central-gravity term for barycentric propagation centers (used bycislunar_default). @duncaneddy (#394)- ECI↔EMBI frame translation helpers
position_eci_to_emb/position_emb_to_eciandstate_eci_to_emb/state_emb_to_eci(Rust + Python). @duncaneddy (#394) - Constants
GM_MARS_SYSTEM–GM_NEPTUNE_SYSTEMandGM_PLUTO_SYSTEM(planetary-system barycentric GMs, NAIFgm_de440.tpc). @duncaneddy (#394) ThirdBody::as_central_body()andThirdBody::body_fixed_frame()helpers (Rust + Python). @duncaneddy (#394)- Standalone example
numerical_propagation/cislunar_earth_forces(EMB-centered propagation with Earth-attributed forces). @duncaneddy (#394) Epoch.to_time_system()(Rust and Python) returns a newEpochfor the same instant expressed in a different time system. The instant is unchanged, so the returned epoch compares equal to the original; only the scale it reports in differs. The method had been referenced by theEpoch::time_systemdocumentation but was never implemented. @duncaneddy (#395)TimeSystemAPI reference page underlibrary_api/time/, documenting all ten time systems (GPS,TAI,TT,UTC,UT1,TDB,TCG,TCB,BDT,GST). It previously lived underconstants/units.mdand listed only five, soTDB,TCG,TCB,BDT, andGSTdid not render at all. @duncaneddy (#395)- "Time System" section in the Learn Epoch guide, covering how an epoch's time system is set and read, and the distinction between converting an epoch and projecting one, with runnable Rust and Python examples. @duncaneddy (#395)
- Example fixtures covering
FLAGSdeclared past the tenth line of a file. @duncaneddy (#395) - FES2004 ocean tide model (
OceanTideModel,OceanTideConfig) with admittance-wave expansion per IERS TN36 §6.3, configurable degree/order up to 100, and one-time cached download of the IERS coefficient file. @duncaneddy (#397) - Solid Earth pole tide (
SolidTideConfig.pole_tide) and ocean pole tide (OceanTideConfig.pole_tide) per IERS TN36 §6.4/§6.5 with the IERS 2018 linear secular pole model (secular_pole,wobble_parameters,solid_earth_pole_tide_deltas,ocean_pole_tide_deltas). @duncaneddy (#397) TidesConfiguration.oceanfield enabling ocean tides in the numerical propagator force model;ForceModelConfig::high_fidelity()now enables solid tides with frequency-dependent corrections, both pole tides, and 30×30 ocean tides. @duncaneddy (#397)- Python bindings for
OceanTideConfigand the newpole_tide/oceanconfiguration fields, with regenerated type stubs. @duncaneddy (#397) ReferenceFrame.Synodic(origin, primary, secondary)andSynodicOriginfor arbitrary two-body rotating frames, withsynodic_origin/synodic_primary/synodic_secondaryaccessors (also populated for EMR/SER/GSE). @duncaneddy (#399)synodic_barycenter_idand generalized synthetic-barycenter resolution in the frame router (Sun-Earth barycenter is now a special case of the generic encoding). @duncaneddy (#399)- Solar System Scope planet texture registry with
download_planet_textureand generalizedload_body_texture(CC BY 4.0, credited in the license page). @duncaneddy (#399) central_bodyandadditional_bodiesparameters onplot_trajectory_3dfor Moon/Mars/custom-body scenes, backed by a body-visuals registry. @duncaneddy (#399)plot_synodic_3dandplot_earth_moon_rotating_3dfor rotating-frame trajectory visualization. @duncaneddy (#399)- Worked examples: LRO lunar orbit, Earth-Moon free return, MRO Mars orbit, Dawn at Ceres (user-defined central body), with learn/API documentation for the new frames and plotting. @duncaneddy (#399)
- Standalone
Rx/Ry/Rzmatrix functions. @duncaneddy (#399) - Planetary radius constants (
R_MERCURY..R_NEPTUNE). @duncaneddy (#399) - Tested learn examples for generic
ReferenceFrame.Synodicframes andplot_earth_moon_rotating_3d. @duncaneddy (#399) - Keplerian ↔ equinoctial element conversions (
state_koe_to_equinoctial,state_equinoctial_to_koe) following the Vallado (eq. 2-99) formulation with Montenbrucka, h, k, p, q, lnaming and an explicit retrograde factor (Rust + Python). @duncaneddy (#403) MeanElementMethodselector (BROUWER_LYDDANEanalytical,numerical(config)windowed averaging) plusWindowAlignment,WindowEdgeHandling,MeanElementNumericalMethodConfig, andMeanElementInverseConfigconfiguration types (Rust + Python). @duncaneddy (#403)- Numerical osculating → mean conversion via windowed averaging in equinoctial space, with trapezoidal time-weighting of the slow elements and configurable window length (seconds), alignment (centered / trailing / leading), and edge handling (truncate / preserve-window). @duncaneddy (#403)
- Numerical mean → osculating conversion via an iterative differential-correction inverse driven by a supplied force model and numerical propagation configuration. @duncaneddy (#403)
- Batch conversion functions
batch_state_koe_osc_to_meanandbatch_state_koe_mean_to_oscreturning(epoch, state)pairs, with Python bindings returning(list[Epoch], ndarray). @duncaneddy (#403) - FK5, Hipparcos, and Tycho-2 star catalog datasets with cached downloads, typed records,
StarRecordtrait, filtering, and Polars DataFrame conversion (Rust + Python). @duncaneddy (#404) - RA/Dec coordinate transformations:
position_radec_to_inertial/position_inertial_to_radec,state_radec_to_inertial/state_inertial_to_radec,position_radec_to_azel/position_azel_to_radec. @duncaneddy (#404) - Rigorous proper-motion epoch propagation
apply_proper_motion(delegating to IAU SOFAiauPmsafeviarsofa; theory per ESA SP-1200 §1.5.5) andStarRecord::radec_at_epoch. @duncaneddy (#404) - Star-field sensor simulation example with animated 3D and sensor-frame Plotly visualizations. @duncaneddy (#404)
datasets::ssn_sensors::load_ssn_sensors/bh.datasets.ssn_sensors.load(): embedded dataset of 21 representative SSN sensor sites from Vallado 4th Ed. Tables 4-2/4-3/4-4 with locations, az/el/range field-of-view limits, and bias/noise calibration values. @duncaneddy (#406)AzElRangeMeasurementModel: topocentric azimuth/elevation/range measurement model with constant-bias support, azimuth residual wrapping, and a wrap-aware finite-difference Jacobian. @duncaneddy (#406)SimpleSSNSensor: ground-sensor measurement simulation with wrap-aware field-of-view checks, seeded Gaussian noise, step-wise (measure) and batched (simulate_observations) generation, and a matching filter-sidemeasurement_model(). @duncaneddy (#406)MeasurementModel::residual(): overridable, dimension-validated residual hook used by all EKF/UKF/BLS residual computations. @duncaneddy (#406)ExtendedKalmanFilter::propagate_to/UnscentedKalmanFilter::propagate_to: measurement-free prediction step that records covariance growth across tracking gaps. @duncaneddy (#406)- SSN tracking examples: standalone Rust/Python pair (
examples/estimation/ssn_tracking) and a six-hour BLS/EKF/UKF walkthrough with sensor-network, measurement, and filter-comparison figures (docs/examples/ssn_tracking.md). @duncaneddy (#406) brahe transform positionandbrahe transform rotationCLI subcommands for position-vector and rotation-matrix transforms between reference frames. @duncaneddy (#407)brahe transform framenow accepts all named reference frames (GCRF, ITRF, EME2000, lunar LCI/LFPA/LFME, Mars MCI/MCMF, EMBI, SSBI, synodic EMR/SER/GSE) in addition to the ECI/ECEF aliases. @duncaneddy (#407)- Runnable
fk5_frame_correctionexample (Python and Rust) demonstrating the star-catalog to EME2000 to GCRF to ITRF transformation chain. @duncaneddy (#413) builder()constructors forDNumericalOrbitPropagator,DNumericalPropagator,SGPPropagator(OMM elements),WalkerConstellationGenerator,ExtendedKalmanFilter,UnscentedKalmanFilter,BatchLeastSquares,AccessProperties, andCDMObjectMetadata, with Python mirrors for all butCDMObjectMetadata. @duncaneddy (#414)WalkerConstellationGeneratorBuilder::build()returns an error on invalid t/p/f configurations instead of panicking. @duncaneddy (#414)CDMObjectMetadataBuilderexposes the optional CCSDS CDM metadata fields thatCDMObjectMetadata::new()could not set, and enforces the conditional-mandatory rules (ALT_COV_TYPErequiresALT_COV_REF_FRAME;EPHEMERIS_NAME=ODMrequiresODM_MSG_LINK). @duncaneddy (#414)- Builder-focused documentation: Learn-page sections, library API pages, and runnable Rust/Python examples for each builder. @duncaneddy (#414)
- JPL Small-Body Database (SBDB) Lookup client (
brahe.datasets.sbdb.SBDBClientreturningSBDBObject) that resolves a name or designation to its NAIF/SPK ID and SI physical parameters (GM in m³/s², radius in m), with on-disk caching. @duncaneddy (#416) - JPL Horizons SPK client (
brahe.datasets.horizons:HorizonsClient,HorizonsSPKRequest,HorizonsSPKResponse) that generates, caches, and loads targeted small-body SPK kernels, with a response handle exposing the cached.bsppath, raw bytes, and a direct load into the SPICE registry. @duncaneddy (#416) - SPK segment type 21 (Extended Modified Difference Arrays) reader, enabling Horizons-generated small-body SPKs (e.g. Ceres) to load and answer position, velocity, and state queries; the interpolation is a port of CSPICE
spke21validated bit-exact against CSPICEspkgeoon a real Ceres kernel. @duncaneddy (#416) - Learn and Library-API documentation pages for the SBDB and Horizons clients. @duncaneddy (#416)
Changed¶
- Breaking: third-body ephemeris accessors renamed from
*_deto*_spice(e.g.sun_position_de→sun_position_spice,accel_third_body_sun_de→accel_third_body_sun_spice) — the ephemeris source is the SPICE kernel system (DE + satellite ephemeris kernels), not DE alone. @duncaneddy (#376) - Breaking: the five outer-planet accessors return the true planet body center (previously the planetary-system barycenter); the barycenter is available via the new
*_barycenter_*_spicefunctions, and third-body force models use those (numerically identical to before, no satellite-kernel downloads in propagation). @duncaneddy (#376) - Breaking: per-body position outputs no longer apply a J2000→ICRF frame-bias rotation. NAIF documents that SPICE "J2000" output from DE kernels is already ICRF-aligned, so the previous rotation introduced a ~23 mas systematic offset (~1.7e4 m at 1 AU). @duncaneddy (#376)
- Breaking:
EphemerisSource::SPKpayload type isSPICEKernel(wasSPKKernel); serde variant names for the DE kernels are unchanged, so serialized force-model configs remain compatible. @duncaneddy (#376) - Switching between DE kernels no longer reloads global state; both kernels stay resident in the registry. @duncaneddy (#376)
ForceModelConfiggains acentral_bodyfield (serde-defaultEarth; existing configs and constructors unchanged) and its validity is now checked at propagator construction instead of failing mid-propagation. @duncaneddy (#377)SolarRadiationPressureConfigurationgainsocculting_bodies(serde-default[Earth], preserving existing behavior). @duncaneddy (#377)state_koe_oscon the numerical propagator now computes osculating elements about the propagator's central body (Earth behavior unchanged; barycenter central bodies return an error). @duncaneddy (#377)CentralBody::Marsand theMCI/MCMFframes are centered on the Mars body center (NAIF 499), with the body-center leg auto-loaded from themar099ssatellite ephemeris (the default DE kernel loads first so a satellite kernel cannot suppress the auto-initialization);ThirdBody::Marskeeps the system barycenter (NAIF 4) per the standard third-body formulation. @duncaneddy (#377)- The lunar PCK / Mars SPK auto-load guards latch on first use (
OnceLock): the kernel registry is consulted once, and unloading kernels mid-run is no longer re-detected (failed loads retry). @duncaneddy (#377) - Kernel-only tests and doctests are no longer integration-gated: SPICE kernels are expected cached locally (
just setup) and in CI; the pytestintegrationmarker is reserved for remote-host access and long runtimes. @duncaneddy (#377) - Rust
ThirdBodyno longer derivesEq/Hash(the newCustomvariant carries a float GM); the PythonThirdBody/CentralBody/OccultingBody/ReferenceFrametypes are plain wrapper classes — equality is preserved but they are not hashable and class attributes are not singletons (use==, notis). @duncaneddy (#377) compute_spherical_harmonicsandaccel_gravity_spherical_harmonicsnow evaluate via the Clenshaw kernel when its coefficients are present (the default), falling back to Cunningham coefficients when those are the only set loaded. @duncaneddy (#378)- Gravity model loading now precomputes only Clenshaw coefficients by default (use
GravityModelCoefficients::Both/Cunninghamfor the V/W kernel);set_max_degree_orderrebuilds whichever coefficient sets exist. @duncaneddy (#378) - The numerical orbit propagator evaluates spherical-harmonic gravity through the Clenshaw kernel (the per-propagator V/W workspace matrices were removed); its per-propagator rotation cache is now an
lru-crate LRU keyed on stage time. @duncaneddy (#378) CLENSHAW_PARALLEL_THRESHOLD_NMAXtuned to 180 from benchmarks (with a TODO to derive it from the execution environment); Cunningham's documented numerical limits added to its rustdoc. @duncaneddy (#378)GravityModel::compute_spherical_harmonics_with_workspaceandaccel_gravity_spherical_harmonics_with_workspace— renamed tocompute_spherical_harmonics_cunningham_with_workspace/accel_gravity_spherical_harmonics_cunningham_with_workspace(the Clenshaw kernel needs no workspace). The old allocating Cunningham entry point is nowGravityModel::compute_spherical_harmonics_cunningham(compute_spherical_harmonicskeeps its name and signature but dispatches). No deprecation aliases retained. @duncaneddy (#378)- Marked additional space-weather tests and integration to issues running locally if celestrak is unavailable. @duncaneddy (#378)
- Numerical propagator construction now applies the configured permanent-tide conversion to propagator-owned gravity models when
ForceModelConfig.tidesis set (models load with C̄20 exactly as published when tides are not configured). @duncaneddy (#385) - Breaking:
ForceModelConfig.third_bodybecomesOption<Vec<ThirdBodyConfiguration>>with per-body entries. The field deserializes from bare bodies, a single entry, a list, or the legacy pre-flattening object shape, which migrates on load with its original semantics (pre-split planet names map to the*Barycentervariants they then denoted). @duncaneddy (#394) - Breaking:
ThirdBody::Mars–Neptunenow denote planet centers (NAIF 499–899, planet-only GMs, resolved through satellite-system kernels) instead of system barycenters; use the new*Barycentervariants for the previous behavior. @duncaneddy (#394) - Breaking:
GM_MARS–GM_NEPTUNEandGM_PLUTOnow hold planet-only GMs from NAIFgm_de440.tpc; the previous DE430-era system values moved toGM_*_SYSTEMand were updated to DE440 (full-precision tpc digits). @duncaneddy (#394) - Force-model validation keys the Earth-atmosphere-model and radius/spin drag requirements on the attributed body rather than the central body, and validates per-third-body gravity models (
EarthZonalrequiresThirdBody::Earth;SphericalHarmonicrequires a body with a known body-fixed frame). An attributed drag body's ephemeris is verified at propagator construction. @duncaneddy (#394) - Renamed the
IGNOREexample flag toNETWORK, completing the split begun in #366.IGNOREnamed no reason to skip, while every file carrying it depends on a live third-party service.--ignorebecomes--networkonjust test-examplesandjust make-plots. @duncaneddy (#395) - Reclassified
plots/fig_access_benchmark.pyandplots/fig_comparative_benchmarks.pyfromIGNOREtoMANUAL. Neither is network-driven: both regenerate committed artifacts and require a custom environment, and neither is driven byjust make-plots. @duncaneddy (#395) - Aligned the User Guide and Python API Reference navigation to a single section ordering and vocabulary. @duncaneddy (#395)
- The Learn time-scale table and the
TimeSystemoverview rustdoc now document all ten time systems rather than five. @duncaneddy (#395) - All tidal corrections (solid Earth Step 1/2, pole tides, ocean tides) and the static gravity field are now evaluated in a single fold-in Clenshaw pass per dynamics call, replacing the separate solid-tide evaluation path. @duncaneddy (#397)
- Bundled EGM2008 gravity model truncated from degree/order 360 to 120 and renamed
GravityModelType::EGM2008_360→EGM2008_120to keep the crates.io package within size limits (bit-identical coefficients through degree 120; higher degrees available via ICGEM). @duncaneddy (#397) - Ocean tide force-model documentation (
docs/learn/orbital_dynamics/tides.md) expanded to cover ocean tides, admittance waves, pole tides, and the download/cache behavior. @duncaneddy (#397) - Documentation is now served from
https://docs.brahe.space/, withbrahe.spaceandwww.brahe.spaceredirecting to it. Existingduncaneddy.github.io/brahe/links continue to resolve through GitHub's permanent redirect. @duncaneddy (#398) - Nightly development wheels now install from
https://docs.brahe.space/simple/. @duncaneddy (#398) - The
git clonecommands in the installation guide now pass-c core.symlinks=trueand clone only themainbranch. @duncaneddy (#398) plot_trajectory_3d:earth_texturerenamed totexture,show_earthrenamed toshow_body, and all parameters aftertrajectoriesare now keyword-only (breaking; all in-repo usages updated). @duncaneddy (#399)load_earth_textureremoved in favor ofload_body_texture. @duncaneddy (#399)just download-resourcesnow also warms the moon/mars/ceres textures. @duncaneddy (#399)state_koe_to_eci_for_body/state_eci_to_koe_for_bodyrenamed tostate_koe_to_inertial_for_body/state_inertial_to_koe_for_body, taking aCentralBodyinstead of a baregmand referencing elements to the body's mean equator at J2000 instead of the ICRF axes. @duncaneddy (#399)- Live-API examples now
NETWORK-flagged. @duncaneddy (#399) - Breaking:
state_koe_osc_to_meanandstate_koe_mean_to_oscnow take aMeanElementMethodargument (beforeangle_format) and return aResult(Rust) / raise on error (Python). Existing analytical behavior is preserved by passingMeanElementMethod::BrouwerLyddane/bh.MeanElementMethod.BROUWER_LYDDANE. @duncaneddy (#403) - Upgraded Rust dependency version requirements to latest compatible releases (
cargo upgrade). @duncaneddy (#404) - UKF measurement statistics use a reference-point mean and residual-based deviations, making the measurement update robust for angular measurements near a wrap (identical results for non-angular models). @duncaneddy (#406)
- EKF/UKF/BLS pre-fit and post-fit residuals now route through
MeasurementModel::residual()(default behavior unchanged). @duncaneddy (#406) rand/rand_distrpromoted from dev-dependencies to runtime dependencies for measurement noise sampling. @duncaneddy (#406)brahe transform framedispatches through the core frame router (state_frame_to_frame) instead of a hardcoded ECI↔ECEF path. @duncaneddy (#407)- Rewrote
docs/examplesnote admonitions as per-example API deep dives coveringGPRecord.to_sgp_propagator,location_accesses,datasets.groundstations.load,AccessPropertyComputer,TimeEventcallbacks,additional_dynamics/control_input,ConstraintAll, andAOIExitEvent. @duncaneddy (#409) - Docs deploys now restore NETWORK-example figures saved by the weekly
--networkintegration run, so example pages no longer reference figures that were never generated. @duncaneddy (#409) - Star-catalog documentation now describes each catalog's native reference frame (Hipparcos and Tycho-2 on ICRS axes, FK5 realizing EME2000) and when the ~23 mas frame bias must be applied before use. @duncaneddy (#413)
DNumericalOrbitPropagatorBuilderis now a runtime builder with required fields asbuilder()arguments, replacing the typestate (Set/Unset) builder; the entry point and setter names are otherwise unchanged (breaking, Rust only). @duncaneddy (#414)DNumericalOrbitPropagator::newandDNumericalPropagator::newvalidateinitial_covariancedimensions against the state dimension and return an error on mismatch. @duncaneddy (#414)- Reworked the Dawn-at-Ceres example to resolve Ceres via SBDB, load a Ceres SPK from Horizons, and model Sun and Jupiter third-body plus solar radiation pressure perturbations around the custom-defined body. @duncaneddy (#416)
- Refactored the SPK reader behind a segment abstraction so a resolved chain can mix segment types, combining a type-21 small-body segment with the existing Chebyshev (types 2 and 3) segments from the DE kernels. @duncaneddy (#416)
- Crates.io and PyPI package-validation CI jobs now run in parallel with the Rust and Python test suites instead of waiting for them to finish. @duncaneddy (#417)
- Getting-started documentation now links function and class references to their corresponding library API and Learn pages. @duncaneddy (#417)
Removed¶
- Breaking:
SPKKernel— useSPICEKernel. @duncaneddy (#376) - Breaking:
datasets::download_de_kernel— usedatasets::naif::download_spice_kernel, which accepts any known kernel name (DE, satellite ephemeris, binary PCK). @duncaneddy (#376) - Breaking:
set_global_almanac,get_loaded_kernel_type, andbrahe_epoch_to_anise(ANISE types no longer appear in the public API). @duncaneddy (#376) - Breaking: ANISE as a runtime dependency (now dev-only). Downstream users relying on brahe's transitive
anisedependency must add it directly. @duncaneddy (#376) GravityModelType::EGM2008_360(renamed toEGM2008_120; not deprecated — the variant was removed outright since the underlying packaged file changed). @duncaneddy (#397)- Internal fixed-size (degree ≤ 4) tidal coefficient evaluator (
TideCoefficients,accel_low_degree_harmonics), superseded by the dynamically sizedTideDeltasaccumulator evaluated through the shared Clenshaw kernel. @duncaneddy (#397) - Removed the Starlink visualization example (
docs/examples/visualizing_starlink.md,examples/examples/visualizing_starlink.py) and its committed figures; the GPS visualization example covers the same workflow. @duncaneddy (#409)
Fixed¶
- ICGEM GFC parser now handles the
gravity_constantheader key and FortranD-exponent notation, unblocking all non-Earth gravity model downloads (e.g. lunar GRGM660PRIM, Mars GMM-2B). @duncaneddy (#377) - Earth-centered propagation configured with the new third-body variants (Phobos, Deimos, Custom) routes through the SPK-backed path instead of panicking;
validate()rejectsLowPrecisionephemerides for bodies other than Sun/Moon and third bodies that coincide with the central body. @duncaneddy (#377) - Repo-wide
cargo fmtandrufflint/format debt that had accumulated since pre-commit hooks were never installed locally. @duncaneddy (#380) crates/brahe-pyclippy errors that were silently exempted from the pre-commit gate because the clippy hook lacked--workspace; the hook now covers the whole workspace. This includedmissing_safety_docon 5 numpy-conversion methods inattitude.rs— on inspection none of them perform an actual unsafe operation (into_pyarray/reshapeare safe in the pinnednumpyversion), so the vestigialunsafekeyword was removed instead of documenting a non-existent invariant — plusnew_without_default/len_without_is_emptyon the EOP provider bindings. @duncaneddy (#380)- Fix issue with some tests that rely on celestrak integration not being properly marked
pytest.mark.integration. @duncaneddy (#385) FLAGSdeclared past the tenth line of an example were silently ignored, because the runner parsed only the first ten lines.lunar_orbit.rsandmars_orbit.rsdeclare theirs on line 13, so both ran on every defaultjust test-examples— downloading the GRGM660PRIM gravity model and themoon_pa_de440kernel — despite being flagged, while their.pytwins were correctly skipped. The runner now parses the whole leading comment block. @duncaneddy (#395)- Corrected the TCG secular drift from
~0.7 s/yearto~22 ms/year(IAU 2000 Resolution B1.9, L_G = 6.969290134e-10). @duncaneddy (#395) - Corrected the
Epoch::time_systemdocumentation, which listed five of the ten time systems and directed readers to ato_time_system()method that did not exist. @duncaneddy (#395) - Corrected typos in the
TimeSystemrustdoc ("supposed" to "supported", "expeccted" to "expected"). @duncaneddy (#395) - Repaired six broken documentation links. The contributing guide, code of conduct, development guide, and license links omitted the
/latest/version segment and resolved to nothing. The development guide was additionally linked asdeveloper_guidelines.html, a page that has never existed. Two versioning policy links used a directory-style URL where the site emits.html. @duncaneddy (#398) brahe transform frameno longer emits duplicate output when the source and target frames are identical (missing early return). @duncaneddy (#407)brahe transform coordinatesnow rejects non-ECI/ECEF values for--from-frame/--to-frameat validation instead of silently mis-routing them. @duncaneddy (#407)- Fixed 404s for all NETWORK-flagged example figures on the live documentation site (Doppler compensation, maximum communications gap, LRO, MRO, Dawn at Ceres, ground contacts, imaging opportunities, imaging data latency, tessellation). @duncaneddy (#409)
- Fixed the NAIF kernel and 3D-texture example caches being stranded on PR merge refs, which forced every CI run into live downloads from naif.jpl.nasa.gov and Solar System Scope; caches now save from main only. @duncaneddy (#409)
- Corrected the NASA NEN station count claim in the ground contacts example note. @duncaneddy (#409)
apply_proper_motiondocumentation now describes the IAU SOFAiauPmsafespace-motion transformation the function actually calls, rather than a hand-rolled tangent-plane method. @duncaneddy (#413)- Documentation figures for the lunar, Mars, Ceres, Earth-Moon free-return, and star-field examples now regenerate on every docs deploy instead of only via the weekly network run. @duncaneddy (#413)
- Mismatched
initial_covariancedimensions previously constructed successfully and panicked inside the first propagation step; construction now fails with a descriptive error, including from Python with extended (6+N) states. @duncaneddy (#414) - Captured output of the NETWORK-flagged getting-started examples (first script, Celestrak client) now reaches the deployed docs through a network-example-outputs cache, and the offline external-data examples emit output, so the affected pages no longer render empty output blocks. @duncaneddy (#417)
- Star-field sensor view no longer flips direction at orbital plane crossings by using the orbit normal as a continuous roll reference, scrolls the star field along the elevation axis, and preserves per-star identity so markers fade in and out instead of jumping when the visible-star count changes. @duncaneddy (#417)
- ci-success aggregation now includes the check-skip and delay-python gating jobs so a failed gate cannot be reported as a passing run. @duncaneddy (#417)
[1.6.2] - 2026-07-01¶
Added¶
- Added native Linux
arm64wheel builds to the latest and release workflows, with platform-specific wheel artifact names to avoid artifact collisions. @hectcastro (#372) CachingEOPProvider/CachingSpaceWeatherProvider(andinitialize_eop()/initialize_sw()) now seed a missing cache from the compiled-in bundled data, so EOP and space-weather initialization succeed offline without an immediate network download. @duncaneddy (#374)- EOP and space-weather downloads now retry transient failures (connection errors, timeouts, HTTP 429/5xx) with exponential backoff and jitter (up to 4 attempts). @duncaneddy (#374)
Changed¶
- Changed standard EOP product source to USNO finals2000A.all. @duncaneddy (#373)
- Changed C04 EOP product source to Paris Observatory C04 Product. @duncaneddy (#373)
- Download failure messages now include the attempted URL and number of attempts. @duncaneddy (#374)
- Consolidated EOP and space-weather download logic into a shared
utils::downloadhelper (internal refactor, no API change). @duncaneddy (#374)
Fixed¶
- Fix compilation issue due to transitive dependency breaking change in
ureq/timecrates. Pintimeuntil issue is resolved. @duncaneddy (#373) - Fixed issue with failing tests due to inability to update outdated EOP products. @duncaneddy (#373)
initialize_eop()/initialize_sw()no longer fail on a fresh/empty cache when the remote EOP or space-weather server is transiently unreachable (e.g.Standard EOP download request failed: io: Connection refusedin CI); bundled data is used instead. @duncaneddy (#374)
[1.6.1] - 2026-06-16¶
Added¶
- Added "Getting Started" section to main documentation page. @duncaneddy (#356)
integrationflag to rust and python test suites, replacingci. @duncaneddy (#365)par_propagate_to(Python) now accepts a list that mixesKeplerianPropagator,SGPPropagator, andNumericalOrbitPropagatorinstances. Propagators are grouped by type and each group is propagated in parallel; results are written back to the original objects in place, preserving list order. @duncaneddy (#366)MANUALexample flag for examples that must never run automatically (scaffolding templates and credential-gated examples), so the--ignorelive-network run no longer sweeps them in. @duncaneddy (#366)
Changed¶
- Update C04 data source to point to currently updating data series. @duncaneddy (#356)
- Makes the
plotssubmodule of the python package an optional dependency installed withbrahe[plots]and not installed by default to avoid importing the heavy dependencies by default. @duncaneddy (#360) - Optimized the serial spherical-harmonic gravity evaluation (
GravityModel::compute_spherical_harmonics/compute_spherical_harmonics_with_workspace) by precomputing the V/W recurrence reciprocal coefficients and reading the recurrence and accumulation buffers through bounds-check-free column slices. The workspace path is ~1.7–1.8× faster at degree/order 20–80 (the range common to LEO propagation) and ~1.6× faster at 360×360, with results unchanged to within 1e-12 relative. Measured on a 10-core Apple M1 Max. @duncaneddy (#361) - Raised the
ParallelMode::Autoparallelization threshold for spherical-harmonic gravity from degree 150 to 210. The faster serial path moved the serial/parallel break-even point, soAutonow stays serial until parallel evaluation is at least as fast. @duncaneddy (#361) compute_spherical_harmonics,compute_spherical_harmonics_with_workspace,accel_gravity_spherical_harmonics, andaccel_gravity_spherical_harmonics_with_workspacenow take aparallel: ParallelModeargument;GravityConfiguration::SphericalHarmonicgained aparallelfield (defaults toAuto). @duncaneddy (#361)- Updated CI workflow to only run integration tests weekly and at release time to reduce frequent occurrence of CI tests failing due to external integration test failures. @duncaneddy (#365)
- Improved CI caching to large texture / basemap files to be updated with integration tests weekly and avoid redownload on most CI runs. @duncaneddy (#365)
- Updated
pyo3dependency version. @duncaneddy (#365) - Updated
uv.lock. @duncaneddy (#365) - Tagged
TEMPLATE.{py,rs}andgetting_started/clients_spacetrack.{py,rs}asMANUALso they are excluded from all automated example runs. @duncaneddy (#366) - Raised the per-example
TIMEOUTto 600s for thestarlink_propagation.pyexamples, which propagate the full live Starlink constellation and exceeded the default 180s limit during the weekly/release live-network run. @duncaneddy (#366)
Removed¶
ciflag from rust and python test suites. @duncaneddy (#365)
Fixed¶
- CSSI space weather data loader has been fixed to use the observed f107 rather than the adjusted f107. @jackyarndley (#362)
- The NRLMSISE-00 implementation has been updated to use the previous day observed f107 as is standard. @jackyarndley (#362)
- Fixed race condition in examples CI tests where two could download the same Natural Earth basemap and corrupt the file for both. @duncaneddy (#365)
- Fixed regression from lazy-impoting
brahe.plotsthat caused static-analyzers (griffee) to fail path-traversal. This causedbuild-docsto fail and slipped through due to other test-failure noise. @duncaneddy (#365) - Fixed
test-examplesflakyness on external integration dependencies. Ignore testing integration-based examples by default, but exercise them weekly in the integration tests to ensure continued coverage. @duncaneddy (#365) par_propagate_to(Python) no longer raisesTypeErrorwhen given a list containing more than one propagator type; mixed-type lists are now propagated correctly. @duncaneddy (#366)- Fixed the release
test-examplesintegration job failing on--ignore:IGNOREwas an overloaded bucket that mixed live-network examples with templates, credential-gated, slow, and broken examples, so opting into the live-network set pulled in examples that could never pass there. @duncaneddy (#366)
[1.6.0] - 2026-06-05¶
Added¶
- Add
RKF78/RKF78Integratorsupport for high-order adaptive integration in Rust and Python. @Mtrya (#339) - Add RKF78 tests, examples, and API/reference documentation. @Mtrya (#339)
- Added GMAT baselines. @duncaneddy (#340)
- Added Basilisk baselines. @duncaneddy (#340)
profiles/subdirectory with short, standalone rust and python scripts for use with profiling tools. @duncaneddy (#341)- Added
justfilecommands to run profiling scripts. @duncaneddy (#341) - Add baselines against Nyx 2.4.0 / ANISE 0.10.1. @duncaneddy (#342)
- Added
datasets.icgemsubmodule to integrate with ICGEM gravity field model distribution network. Listing and downloading models uses the local brahe cache to minimize network traffic. @duncaneddy (#343) - Added brahe vs astrojax benchmarks. @duncaneddy (#344)
- Add
ci-successstage to enable gating CI auto-merge on completion. @duncaneddy (#350)
Changed¶
- Extend numerical propagation integrator selection and comparison examples to include RKF78. @Mtrya (#339)
- Split baselines into speed and accuracy tests. @duncaneddy (#340)
- Added
ICGEMModel(body, model_name)toGravityModelTypeenabling ICGEM models to be specified for numerical orbit propagators. @duncaneddy (#343) - Scaled back python-version test matrix on PRs to minimum supported python version. @duncaneddy (#345)
- Removed
anisedefault feature dependency to just pull in SPICE kernel features. @duncaneddy (#350)
Fixed¶
EulerAngleOrdersemantics now match what brahe's documentation always described and what the comparative benchmark expects. Prior to this fix,attitude.euler_angle_to_quaterniondisagreed with OreKit, GMAT, and Basilisk. The discrepancy was traced through to a convention mismatch between the per-order formulas (faithfully transcribed from Diebel 2006) and the aerospace rotation-sequence interpretation users (and the docs) assumed. @duncaneddy (#338)- Fixed issue with CHANGELOG parsing in PRs where a blank line after a section header would fail to validate. @duncaneddy (#338)
- Fixed issue with Orekit access baseline not properly inserting leap seconds in accuracy computation leading to in accurate error. @duncaneddy (#340)
- Fixed build breaking from conflicting
nalgebrarequired dependencies. @duncaneddy (#350) - Regression in use of custom python-based access constraints where they would give an error at use. @nkgotcode @duncaneddy (#354)
[1.5.2] - 2026-05-18¶
Fixed¶
- Fix issue with new release workflow
CHANGELOGgeneration that would result in an error causing the release to fail. Release notes now must be manually generated and committed prior to running the release action. @duncaneddy (#334)
[1.5.1] - 2026-05-18¶
Added¶
DNumericalOrbitPropagator::builder()- typestate builder that names required fields and lets optional fields be set by name or omitted.build()is only callable onceepoch,state, andforce_configare all set, enforced viaSet/Unsetmarker type parameters. @markusz (#321)- Added
states_ecefandstates_eme2000toSGPPropagator. @duncaneddy (#331) - Added
states_eme2000toKeplerianPropagator. @duncaneddy (#331) - Added
states_eci,states_ecef,states_gcrf,states_itrf, andstates_eme2000toNumericalOrbitPropagator. @duncaneddy (#331) - Added
statestoNumericalPropagator. @duncaneddy (#331) - New high-fidelity propagator benchmarks under
benchmarks/comparative/tasks/propagation_tasks.py:numerical_rk4_grav5x5,numerical_rk4_grav20x20_sun_moon,numerical_rk4_grav80x80_full. Each runs RK4 over one LEO revolution with matched force-model and frame settings on both sides (OreKit loads brahe'sEGM2008_360.gfcviaICGEMFormatReader, GCRF inertial frame, ITRF / IAU 2006/2000A body-fixed rotation, DE-440 third-body ephemerides, identical spacecraft mass / area / Cd / Cr). @duncaneddy (#332) - New function-level acceleration benchmarks under
benchmarks/comparative/tasks/force_model_tasks.pyfor point-mass gravity, 20×20 and 80×80 spherical-harmonic gravity, and third-body Sun/Moon. These evaluate a single acceleration at a fixed state and epoch, isolating force-model code from integrator behaviour. @duncaneddy (#332) - "Force Model" section in
docs/about/benchmarks.mddocumenting the new function-level comparisons. @duncaneddy (#332) GravityModel::load_uncached(model)— explicit cold-load primitive for users who need deterministic memory or want to profile the parse path. @duncaneddy (#332)GravityModel::compute_spherical_harmonics_with_workspace(...)andaccel_gravity_spherical_harmonics_with_workspace(...)— variants that accept caller-supplied V/W work matrices, letting hot-path callers (the numerical propagator's dynamics closure, batch orbit-determination residual code) amortize the per-callDMatrix::zeros((n_max + 2)²)allocation. At 80×80 the saved allocation+memset is ~15 µs per call. @duncaneddy (#332)clear_gravity_model_cache()— manual cache invalidation, useful after replacing aFromFile(path)source on disk or in tests. @duncaneddy (#332)mimallocas the global allocator for thebrahe-pyPython extension and the comparative-benchmark Rust binary. The brahe core library remains allocator-agnostic so downstream Rust consumers pick their own. @duncaneddy (#332)- Added
SECONDS_PER_DAYconstant. @duncaneddy (#333)
Changed¶
NumericalOrbitPropagatorandNumericalPropagatornow no longer store accelerations by default to save space and improve performance. @duncaneddy (#330)- The FD fallback for HermiteQuintic is removed. Previously, calling HermiteQuintic on a trajectory without stored accelerations would silently degrade to finite-difference acceleration estimation if 3+ points were available; now it errors. Combined with the earlier store_accelerations: false default flip, any code path that today uses HermiteQuintic either needs NumericalPropagationConfig::with_store_accelerations(true) (propagator path) or trajectory.enable_acceleration_storage() (direct path). @duncaneddy (#330)
- Performance, numerical propagator (no behaviour change): the
DNumericalOrbitPropagatorhot path now caches the ECI→body-fixed rotation across integrator stages, shares oneArc<GravityModel>across propagators with the same gravity config (no more 60 ms.gfcreload per construction), borrows the state vector instead of cloning it on every stage call, returns the orbital derivative as a stack-allocatedVector6<f64>instead of allocating a freshDVector, and reuses the spherical-harmonic V/W work matrices across stages. @duncaneddy (#332) GravityModel::from_model_typeis now process-wide cache-backed. Repeated calls for the sameGravityModelTypeparse the.gfcfile once (~60 ms cold), then return owned clones from the cachedArc(~1 ms each). The public signature is unchanged. Cache is documented as unbounded — see the# Cautionblock on the function for the growth caveat with many distinctFromFile(path)sources, and useclear_gravity_model_cache()as the escape hatch. @duncaneddy (#332)bias_precession_nutationswitched fromiauXys06a(full IAU 2000A nutation, ~1300 terms) toiauXys00b(truncated IAU 2000B, ~77 terms). Per-call cost dropped from ~150 µs to ~2.3 µs; agreement with the full series is sub-milliarcsecond, no regressions in tests. @duncaneddy (#332)- Refreshed benchmark plots and docs. @duncaneddy (#332)
- Changed how adding a flaot second time to an Epoch (
epc + 42.5) processes the internal addition. Previously, it would loop of remaining nanoseconds and convert them into integer seconds. For large second values, this would result in many loops for a single step, meaning that time addition, a frequent code hot-path, would grow linearly in time. Now it is an O(1) operation. @duncaneddy (#333)
Fixed¶
- Update urllib3 to mitigate security vulnerability. @duncaneddy (#326)
- Some estimation plots used unicode sigma instead of
$\sigma$. When latex is installed and defaults to pdfLaTeX compiler, this causes an error. Switch to$\sigma$everywhere. @duncaneddy (#331) DNumericalOrbitPropagator::propagate_tomay hang with fixed-step RK4. Atsrc/propagators/dnumerical_orbit_propagator.rs:2312the restore-dt_nextguard used>instead of>=. Withtarget_epoch = epc + N * step_sizeconstructed by repeated arithmetic, float drift could leavetarget_relslightly larger than the integer multiple; Fixed by changing the comparison to>=so the restore fires whenever the integrator returned its preferred step. @duncaneddy (#332)- Workspace mismatch in
benchmarks/comparative/implementations/rust/Cargo.toml: the crate predated the brahe repo-root workspace and would fail with "current package believes it's in a workspace when it's not". Added an empty[workspace]table so cargo treats the bench as its own workspace root. @duncaneddy (#332)
[1.5.0] - 2026-05-06¶
Added¶
- Added
accel_earth_zonal_gravity— a hand-rolled closed-form J2–J6 zonal acceleration that mirrorsaccel_gravity_spherical_harmonicswithm = 0but evaluates ~1.5–2x faster, with agreement to <3 km over a 24 h LEO propagation when both are driven in the same Earth-fixed frame. @markusz (#302) - Added
GravityConfiguration::EarthZonal { degree }variant and supportingZonalHarmonicsDegreeenum (J2..J6) so the numerical propagator can use the fast zonal path directly. @markusz (#302) - Added
FrameTransformationModel(variantsFullEarthRotation,EarthRotationOnly) and aframe_transformfield onForceModelConfig.EarthRotationOnlyskips precession, nutation, and polar motion for ~1.5x faster ECI↔ECEF rotations at the cost of ~0.07° pole-tilt accuracy;FullEarthRotation(default) preserves prior behavior. @markusz (#302) - Added
J3_EARTH,J4_EARTH,J5_EARTH, andJ6_EARTHconstants derived from EGM2008. @markusz (#302) - Added Python bindings for
accel_earth_zonal_gravity,ZonalHarmonicsDegree,FrameTransformationModel,GravityConfiguration.earth_zonal(...), and the newJ3_EARTH–J6_EARTHconstants. @markusz (#302) - Added coefficient-derivation tests verifying each
J_n_EARTHconstant matches-C_n,0 * sqrt(2n + 1)against the EGM2008 fully-normalized Stokes coefficients. @markusz (#302)
Changed¶
- Refined
J2_EARTHto be derived from the EGM2008C_2,0Stokes coefficient (1.0826261738522227e-3) instead of GGM05s. Downstream values change in the 5th significant digit. @markusz (#302) - Reused a single ECI→body-fixed rotation per dynamics step across gravity, NRLMSISE-00 density, and drag inside
DNumericalOrbitPropagatorrather than recomputing the rotation per force term. @markusz (#302) - Update package lockfile. @duncaneddy (#306)
Removed¶
- Removed rust artifact caching from CI since existing rust environment already provides (working) caching. @duncaneddy (#315)
Fixed¶
- Add missing
CHANGELOG.mdrelease entries. @duncaneddy (#306) - Fix error with release note generation step of release workflow. @duncaneddy (#306)
- Fix issue with awk-based release-note generation step of release workflow not populating release note contents. @duncaneddy (#306)
- Fixed Starlink examples and documentation prose that still referenced the removed
bh.datasets.celestrak/bh::datasets::celestrakAPI. @Mtrya (#310) - Fix 3rd party changes PRs not generating changelog fragments. @duncaneddy (#317)
[1.4.2] - 2026-04-23¶
Fixed¶
- Fix
brahe-pyCrate not using rootCargo.tomlas single-source-of-truth for package version. #298 - Corrected
format_exponentialexponent offset in TLE generation (#300). BSTAR and second time derivative values are no longer 10x too small.
[1.4.1] - 2026-04-21¶
Changed¶
- Improve documentation around versioning practices. #282
- Add deprecation section to changelog #284
- Bump version for v1.4.1 release #295
Fixed¶
- Fix a permissions issue that pervented CHANGELOG validation from running on fork PRs #293
[1.4.0] - 2026-04-17¶
Added¶
Changed¶
- Refactored repository structure to use a Rust workspace to breakup the python module from the core rust module. This pure-rust package consumers to avoid having to build the
cdylib, which is only needed for python module builds. #278 pyo3andnumpyare now optional dependencies, activated via thepythonfeature flag. Pure-Rust consumers that do not need the Python bindings no longer compile these crates.- Split the repository into a Cargo workspace so the PyO3 bindings live in a dedicated
brahe-pymember crate atcrates/brahe-py/. The publishedbrahecrate now builds only anrlib, eliminating the unnecessarycdylibartifact previously produced for every pure-Rust consumer. Rust downstream (use brahe::*) and Python downstream (import brahe) are unchanged.
Fixed¶
- Fixed issue that would cause tests and auto-merge to not run on dependabot PRs #278
[1.3.4] - 2026-04-15¶
Fixed¶
- Fix failing celestrak queries by migrating from celestrak.com to celestrak.org #272
[1.3.3] - 2026-04-10¶
Added¶
- Add JD_J2000 constant to python bindings #264
[1.3.2] - 2026-04-06¶
Changed¶
- Updated JOSS manuscript to comply with latest guidelines #256
Fixed¶
- Fixed issue with SGP4 propagators erroring during parallel propagation on satellite reentry. Addressed by adding a
termination_errorfield to SGPPropagators which will be documented and stop propagation rather than erroring all propagation. Issued with documentation builds in CI failing due to dependency changes. Fixed by updatinguv.lock#256
[1.3.1] - 2026-03-29¶
Added¶
- Added retry logic and exponential back-off to Celestrak client Added process-based rate-limiting to Celestrak client #244
Changed¶
Fixed¶
- Pointed
mikedocumentation deployment to useproperdocs.yml#244 - Fix
mike set-defaultinvocation to useproperdocs.ymlconfig #246
[1.3.0] - 2026-03-29¶
Added¶
- Added python constructors for CCSDS OPM and OMM file types #225
- Added dedicated
celestrakandspacetracksubmodules to the brahe CLI for querying and interfacing with space track. Addedto_dict()andto_json()methods for GPRecord python module to enable easy interoperability #227 - Added additional python test coverage #228
- Added
estimationmodule with support forEKF,UKF, andBLS(batched least-squares) filters Added estimation plotting routines Added implementations of magnetic field models. In particular the IGRF and WMMHR models. Addedfrom_unix_timestampandunix_timestampmethods to support interoperability with native unix time systems Added sponsor logo #241
Changed¶
- Added additional test coverage #225
- Renamed
MJD2000constant toMJD_J2000to align withJD_J2000naming #231 - Improved documentation code samples by auto-generating, capturing, and rendering script outputs so values are guaranteed to be kept up to date. #234
- Migrated to
properdocsfrommkdocsfor documentation due to instability in project. #241
Fixed¶
- Fixed issue with anomaly conversion CLI not properly using
use_degrees#225
[1.2.0] - 2026-03-21¶
Added¶
- Added polygon tessellation for large area access computation #199
- Added additional benchmarks and comparisons to OreKit in
benchmarks/comparisons#209 - Add support for CCSDS OEM, OMM, OPM (blue-book) and CDM (pinkbook) types. Methods exist to load, access, modify, and create these data objects. #214
- Add full support for XML and JSON output across OEM, OPM, and OMM files. #222
Changed¶
- Have Propagators set a UUID by default Have Locations set a UUID by default Migrated default-generated UUIDs to UUIDv7 #202
- Removed
releaseenvironment flag from github release workflows Only retain last 3 minor documentation verions to prevent unbounded growth of github pages deployments. #209 - Cleaned up space-track and celestrak documentation to improve readability and understandability #214
- Added coverage reporting for python bindings and module #218
- Improved CCSDS module round trip test coverage Ensures that default OEM to Trajectory conversion returns a
DOrbitTrajectoryso that it can immediately be used with access computation. #222
Fixed¶
- Reverted compilation regression due to dependabot update. Ignored packages to prevent future regressions #194
- Skip running CI-related tests on fork-PRs so that tests pass. #204
- Changes access module type annotations from
ListtoSequenceso that LSPs don't erroneously report a warning thatlocation_accessesand other functions might mutate the list. Fix issue where python bindings for access properties would return a copy of the underlying data so mutations would not persist. IntroduceAccessPropertyViewso that it is now properly possible to access, set, and modify access properties in python. #206 - Fixed issue with Gabbard plots not generating properly #218
- Fix coverage reporting #220
[1.1.4] - 2026-03-05¶
Fixed¶
- Fix regression from dependabot update Included type annotations in package generation #188
[1.1.3] - 2026-03-04¶
Added¶
- Added
SubdivisionConfiga subfield ofAccessSearchConfigto control how subdivisions are created #181
Changed¶
- Migrated to PyO3
v0.28Update Cargo dependencies #179 - Removed
time_stepparameter from internalfind_access_windowsmethod. Configuration of stepping and subdivision is now unified as a property ofAccessSearchConfig#181
Fixed¶
- Fixed issue in dataframe creation from dependabot update. #179
[1.1.2] - 2026-02-14¶
Fixed¶
- Fix spacetrack client erroring out when query returns a lot of results
- Fix spacetrack
cdm_publicroute having wrong parent stem #169
[1.1.1] - 2026-02-14¶
Added¶
- Added ability to configure
TrajectoryModeonSGP4Propagatorfor applications where memory-use management is key. #167
Changed¶
- The JOSS paper submission used code examples with the older celestrak API. This PR updates the code examples to use the updated, stabilized API.
- Slightly adjust language in paper to avoid silly page overflow #165
- Changed default interpolator used by
NumericalOrbitPropgatorfor event detection from linear to 3rd degree Hermite. #167
Fixed¶
- Make
.current_epoch()property a method, not property in python bindings. - Fixed issue with event detection system in
NumericalOrbitPropagatorwhere it not correctly process events co-located with the current time, and would sometimes miss events in between time steps. #167
[1.1.0] - 2026-02-10¶
Added¶
- Added
par_propagate_to_dmethod. #109 - Add Github issue templates for bugs and feature requests #113
- Add arXiv citation to README and documentation. #124
- Modified python bindings to support access computation with numerical orbit propagators. #126
- Added
spacetrackclient module, enabling direct interaction with space-track.org APIs #150 - Added BSL-1.0 to allowed dependency license list
- Added GCAT dataset interface #152
- Added simplified
CelestrakClientinterface to bridge gap between new interface and old one. #157
Changed¶
- Bump version for 1.0.1 release #106
- Renamed
par_propagate_totopar_propagate_to_s - Move SGPPropagator to D-Type event detection. #109
- Update documentation to add JOSS paper submission badge. #113
- Update JOSS workflow to export tex artifacts to support arXiv upload. #122
- Moved all Brahe errors in python bindings from
OSErrortoBraheErrorto make them more distinguishable and easy to handle. #126 - Updated JOSS paper with new required sections. #137
- Enable manual triggering of latest documentation build in CI for handling EOP-update edge cases for releases. #139
- Overhauled
celestrakclient. Thecelestrakclient now uses a common type and query structure shared with thespacetrackmodule. In particular, theGPRecordserves as the common representation of OMM elements returned by both sites. This enables greater interoperability between other library modules that can consume or act onGPRecordtypes. Thecelestrakmodule is now it's own, stand-alone, module independent ofdatasets. - Migrate developer workflow from
make.pyto just - Remove dependency on BTreeCursor nightly feature, allowing crate to compile with stable rust. #150
- Adjusted
CelestrakQuerypython bindings to properly use properties instead of methods for specific dataset queries. Example: New:CelestrakQuery.gpvs Old:CelestrakQuery.gp()#157
Fixed¶
- Enabled event detection in
par_propagate_tomethod in Python #109 - Fixed broken documentation links in readme. (Thank you Stuart Bartlett for pointing it out) #129
- Fix broken links in main documentation landing page. #131
- Fix provider names for SSC stations in NASA Near Earth Network #143
- Fix https://duncaneddy.github.io/brahe/ to redirect to the current default root URL. #147
- Fixed tables in ephemeris documentation not being justified. #152
- Reverted
pyo3version update due to incompatibility withnumpydepdency - Prevented dependabot from auto-updating
pyo3#157 - Properly pass environment secrets from the
releaseworkflow to child-workflows #159
[1.0.1] - 2025-12-04¶
Added¶
- Added
from_omm_elementstoSGPPropagator. Supports direct initialization of propagator from OMM elements without needing to go through TLE lines. This is both more accurate as well as more robust to TLE ID depletion. #102 - Add support for event detection to
SGPPropagator - Add
AOIEntryEventandAOIExitEventas premade event detectors. #104
Fixed¶
- Fix typo in JOSS paper title #99
[1.0.0] - 2025-11-29¶
Added¶
{D}NumericalOrbitPropagatorand python bindings{D}NumericalPropagatorand python bindings- Event detection system for numerical propagators to find events during propagation #89
- Mean to osculating, osculating to mean orbital element transformations
- Update OrbitStateProviders to provide
state(s)_koe_meanandstate(s)_koe_osc - Implement ECI<>ROE direct transformations
- Add
ephemeris_agetoSGPPropagator - Implement Largrange, cubic Hermite, and quintic Hermite interpolation methods.
- Add
WalkerConstellationGeneratorwhich enables rapidly generating propagators with walker-geometry configurations. #96
Changed¶
- Make access computation use D-type propagators.
- Standardize on
- Add support for D-type returns to
KeplerianPropagatorandSGPPropagator - Standardized trait traits for
{S|D}StateProvider,{S|D}CovarianceProvider,{S|D}StatePropagator DTrajectoryandDOrbitTrajectorycan now store trajectories of arbitrary lengthDTrajectoryandDOrbitTrajectorycan now store stm and sensitivity matricies alongside state and covariance.- Improved test coverage across modules
- Changed how third-body ephemeris sources are defined and loaded. DE source is now a parameter instead of set by function name. Dynamically load BSP files when called.
- Changed how Gravity models are defined in terms of enumeration types.
- Renamed
state_cartesian_to_osculatingandstate_osculating_to_cartesianasstate_eci_to_koeandstate_koe_to_eci#89 - Improve trajectory module test coverage
- Improve events module test coverage
- Changed CI release workflow to publish documentation updates only after packages have been successfully published #96
Fixed¶
- Numerical integration
stepandstep_with_varmatnow take explicit parameter values. #89
Removed¶
- Removed
STrajectory6from python bindings. #89
[0.4.0] - 2025-11-28¶
Added¶
- Add space weather data management and access modeled on Earth orientation data provider design. #73
- Added support for control inputs to numerical integration
- Added support for integration of sensitivity matrices to numerical integration functions
- Added support for analytical and numerical computation of sensitivity matrix
- Added documentation for integration with control inputs and sensitivity matrix integration
- Added documentation for computation and handling of sensitivity matrices #78
- Add JOSS draft paper #80
- Added NRLMSISE-00 atmospheric density model implementation #82
Changed¶
- Consolidates internal implementation of numerical integration
- Added additional numerical integration tests to improve coverage
- Consolidates duplicate type definitions across integrator files #78
- Refactor
celestrak.rsandnaif.rsmodules to useHttpClientstructure to enable mocking and mock testing through mockall to make struct calls - Refactored main package documentation #84
Fixed¶
- Auto-merge of bundled data update wasn't auto-merging #75
- Removed erroring cache-check in python test workflow #78
[0.3.0] - 2025-11-18¶
Added¶
- Added
Integratorssubmodule with complete rust implementation, python bindings, documentation, and examples - Support for
RK4,RKF45,DP54, andRKN1210numerical integration methods - License validation and compliance checks. Package is now automatically checked to ensure all dependencies have permissive, commercially-adoptable licenses #63
- NAIF Development Ephemeride dataset download and caching
- High-accuracy DE440s-based ephemeris prediction
- High-accuracy DE440s-based third-body acceleration prediction
- Python bindings for orbit dynamics functions #68
- Added
geo_smafunction to directly return the semi-major axis needed for a geostationary orbit. #69
Changed¶
- Moved mathematics capabilities from
utilssubmodule to dedicatedmathsubmodule. - Bumped version to
0.2.0for release - Removed Rust test sections from coverage reporting #63
- Orbit dynamics functions which previously required a position-only vector can now accept either a position-only or a state vector. Conversion will be handled by the
IntoPositiontrait. #68
Fixed¶
- Fix inconsistencies in Python API reference header levels
- Missing Ground station
- Miscellaneous documentation improvements and fixes #63
[0.2.0] - 2025-11-17¶
Added¶
- Added
relative_motionsubmodule to contain functionality related to relative motion - Implemented RTN rotation and state transformations:
rotation_eci_to_rtn,rotation_rtn_to_eci,state_eci_to_rtn, andstate_rtn_to_eci - Implemented Relative Orbital Element (ROE) state transformations
state_oe_to_roeandstate_roe_to_oe - Added
util::mathfunctionssqrtmandspd_sqrtmto calculate matrix square root - Added
util::mathfunctionsoe_to_radiansandoe_to_degreesto reduce duplication in converting angle values in orbital element calcualtions #57 - Implement
CovarianceProvidertrait forOrbitTrajectory. Providescovariance,covariance_eci,covariance_gcrf, andcovariance_rtn - Add
interpolationsubmodule to store consistent covariance interpolation methods - Implement covariance rotation from ECI to RTN frame
- Extends
OrbitTrajectoryto optionally store covariance information. #59
Changed¶
- Don't run PR tests on release CHANGELOG update. #49
- Unit test and PR test workflows now cancel in-progress runs if a new commit lands
- Added concurrency guards to auto-merge workflows. #53
- Moved where internal vector/matrix (e.g.
SMatrix3,SVector6) type aliases are defined fromcoordinatessubmodule toutils#57
Fixed¶
- Don't trigger multiple changelog merges on changelog a PR. #49
- Only trigger auto-merge on
openeddue to changelog PRs not issuinglabeledevents #51 - Added additional triggers to auto-merge workflows to ensure they are properly triggered. #53
- Fixed assorted typos and errors in docstrings related to covariance interpolation features. #61
- Fixes package-data update CI workflow by moving to auto-PR, auto-merge approach #64
[0.1.3] - 2025-11-12¶
Added¶
- Added python missing bindings for
states_icrfandstates_gcrfforKeplerianPropagatorandSGPPropagator - Added additional tests across various module to improve test coverage. #36
Changed¶
- Refactor
frames.rsfile into submodule with subfiles for long-term maintainability. #14 - Automatically create and merge PRs for changelog updates #16
- Auto-merge changelog PRs
- Auto-merge dependabot PRs
- Expand dependabot to cover python and rust packages #26
- Bump package version to
v0.1.3#34 - Skip unit test suite on auto-generated changelog PRs. #44
Fixed¶
- PR changelogs were not being incorporated into the package changelog due to main-branch protection #16
- Stop generation changelog PRs for auto-generated changelog PRs #26
- Fixed issue with release pipeline release note generation #38
- Fix auto-merge for changelog PRs by using PAT #40
- Fix auto-merge workflow to accept PAT owner as actor. #42
- Fix workflow release step to use workflow PAT and declare base branch #46