astrodyn_dynamics 0.2.0

Rigid-body dynamics, integrators (RK4, RKF45, GJ, ABM4), mass tree, and body initialization
Documentation

astrodyn_dynamics

Rigid-body dynamics, integrators (RK4, RKF45, Gauss-Jackson, ABM4), the mass tree, and body initialization for the astrodyn_bevy workspace.

Ports models/dynamics/ and models/utils/integration/ from NASA JEOD v5.4.0. Decomposes JEOD's 1200-line DynBody god-class into ~10 narrow components.

When to use

  • Propagating a rigid body's state — translational (3-DOF) or full 6-DOF — through an RK4, RKF45, Adams-Bashforth-Moulton, or Gauss-Jackson integrator step.
  • Composing mass trees with parallel-axis-theorem (Steiner) contributions from offset child masses, and re-deriving the composite center of mass / inertia tensor after attach / detach.
  • Initializing a body from orbital elements, mean anomaly, time-since-periapsis, LVLH, or NED — all five JEOD BodyAction pathways are ported.
  • Pre-/post-step frame propagation — moving state between a body's structure, composite_body, and core_body frames, and applying holonomic constraints (tethers, articulated joints).

Mission code rarely calls into this crate directly; the VehicleBuilder typestate in astrodyn and the astrodyn_bevy components wrap these primitives. Reach for astrodyn_dynamics directly when porting JEOD BodyAction subclasses, when adding a new integrator, or when implementing a custom constraint.

Key concepts

Translational state is stored absolute in the integration frame (typically J2000 ECI), not parent-relative — this is the JEOD convention and it's enforced at the type level via TranslationalStateTyped<IntegrationFrame>. Consumers that require root-inertial coordinates (gravity, SRP, solar beta, Earth lighting) must apply the integration-origin shift through body.trans.to_inertial(&integ_origin); the compiler refuses to pass integration-frame state where root-inertial is required. See RF.10 in docs/JEOD_invariants.md for the structural rationale.

Mass properties carry both mass and the pre-computed inverse_mass (similarly inertia and inverse_inertia), refreshed once per step so the inner force-to-acceleration loop is multiply-only. The MassTree keeps subtree composition in Steiner form, so a leaf re-attach updates the composite CoM / inertia at the root via the same algorithm JEOD uses. Integrators (rk4_*, rkf45, abm4, gauss_jackson) all reduce to the same per-stage derivative call (compute_translational_derivatives / compute_frame_derivatives), so adding a new integrator is purely adding a new dispatch arm to IntegrationMethod.

Layered architecture

astrodyn_bevy        (Bevy ECS adapter, mission code)
   ↓
astrodyn         (orchestration, recipes)
   ↓
astrodyn_dynamics    ←  this crate (pure Rust, zero Bevy)
   ↓
astrodyn_math, astrodyn_frames, astrodyn_quantities

Public surface

  • state::TranslationalState, rotational::RotationalState, rotational::SixDofState — body state in the integration frame.
  • mass::MassProperties — mass, inertia, CoM offset, plus the parallel-axis (Steiner) composition for mass-tree subtrees.
  • forces::TotalForce, forces::FrameDerivatives, forces::DynamicsConfig, forces::GravityAcceleration — per-step force / derivative accumulators.
  • integration::IntegrationMethod — RK4 / RKF45 / GJ / ABM4 dispatch.
  • propagation, subtree, attach, body_init, constraints, mass_body — the rest of the DynBody decomposition.

JEOD conventions

  • Translational state is stored in the integration frame (typically J2000 ECI), absolute (not parent-frame-relative). Typed clients use TranslationalStateTyped<F>; the runner pins F = astrodyn_quantities::IntegrationFrame so consumers requiring root-inertial coordinates (gravity, SRP, solar beta, earth lighting) must apply the integration-origin shift via body.trans.to_inertial(&integ_origin) — a compile error otherwise. See issue #255 / RF.10 in docs/JEOD_invariants.md.
  • Quaternions are scalar-first left-transformation (astrodyn_math::JeodQuat).
  • inverse_mass and inverse_inertia are pre-computed once per step to keep the inner loop multiply-only.

See also