koenig_damico_planner/lib.rs
1//! # koenig-damico-planner
2//!
3//! Faithful Rust re-implementation of Koenig & D'Amico's fuel-optimal impulsive
4//! control algorithm (IEEE TAC 2020; see the References below).
5//!
6//! ## Quick start
7//!
8//! ```no_run
9//! use koenig_damico_planner::{solve, Pseudostate, SolveParams, TimeGrid};
10//! use koenig_damico_planner::dynamics::{AbsoluteOrbit, J2Roe};
11//! use koenig_damico_planner::cost::Piecewise;
12//! use std::f64::consts::TAU;
13//!
14//! let a_c = 25_000e3; // chief semimajor axis [m], the I/O scale factor
15//! let chief = AbsoluteOrbit::new(
16//! a_c, 0.7, 40f64.to_radians(), 358f64.to_radians(), 0.0, 180f64.to_radians(),
17//! );
18//! let dynamics = J2Roe::new(chief, 0.0, 117_990.0)?; // validates the chief
19//! let grid = TimeGrid::uniform(0.0, 117_990.0, 30.0)?; // validates dt > 0, t_f > t_i
20//! let cost = Piecewise::new(TAU / chief.mean_motion())?; // validates period > 0
21//! let w = Pseudostate::from_row_slice(&[50.0, 5000.0, 100.0, 100.0, 0.0, 400.0]) / a_c;
22//!
23//! let solution = solve(&dynamics, &cost, w, grid, &SolveParams::default())?;
24//! println!("{} maneuvers, total dv = {:.4} mm/s",
25//! solution.maneuvers.len(), solution.total_dv * 1e3);
26//! # Ok::<(), koenig_damico_planner::PlannerError>(())
27//! ```
28//!
29//! The concrete built-ins a caller instantiates live in the submodules:
30//! `dynamics::{AbsoluteOrbit, J2Roe}` (the only [`Dynamics`] implementor) and
31//! `cost::{Piecewise, Norm2, FaceMax}` (the [`CostModel`] / [`SublevelSet`]
32//! implementors). A runnable version of the above is `examples/mdot.rs`
33//! (`cargo run --example mdot`).
34//!
35//! ## Features
36//!
37//! - **`serde`** *(off by default)* — derives `Serialize`/`Deserialize` on the
38//! public result/wire types ([`Solution`], [`Maneuver`], [`TimeGrid`],
39//! [`SolveParams`], [`PlannerError`], [`InvalidInputKind`], and
40//! `dynamics::AbsoluteOrbit`) for the JSON request/response contract. docs.rs
41//! renders the crate with this feature enabled.
42//!
43//! ## References
44//!
45//! Functions throughout the crate carry a `Ref:` comment citing the equation,
46//! table, algorithm, or figure they implement, using these short keys:
47//!
48//! - **\[KD20\]** A. W. Koenig and S. D'Amico, "Fast Algorithm for Fuel-Optimal
49//! Impulsive Control of Linear Systems with Time-Varying Cost," *IEEE
50//! Transactions on Automatic Control*, 2020. DOI: 10.1109/TAC.2020.3027804
51//! (arXiv:1804.06099).
52//! - **\[KGD17\]** A. W. Koenig, T. Guffanti, and S. D'Amico, "New State
53//! Transition Matrices for Spacecraft Relative Motion in Perturbed Orbits,"
54//! *Journal of Guidance, Control, and Dynamics*, 2017. DOI: 10.2514/1.G002409.
55//! - **\[CD18\]** M. Chernick and S. D'Amico, "Closed-Form Optimal Impulsive
56//! Control of Spacecraft Formations Using Reachable Set Theory," AAS 18-308,
57//! 2018.
58//! - **\[H25\]** M. Hunter and S. D'Amico, "Fast Fuel-Optimal Constrained
59//! Impulsive Control with Application to Distributed Spacecraft," *Proc. IEEE
60//! Aerospace Conference*, 2025.
61
62// Require every public fallible or panicking fn to document how it can fail.
63#![warn(clippy::missing_errors_doc, clippy::missing_panics_doc)]
64
65pub mod algorithm;
66pub mod cost;
67pub mod dynamics;
68pub mod solver;
69pub mod types;
70
71// --- Core API: the entry points and results most users need. ---
72pub use algorithm::{primer_history, solve, solve_from_initial_times, PrimerHistory};
73pub use dynamics::Dynamics;
74pub use types::{
75 ErrorClass, InvalidInputKind, Maneuver, PlannerError, Solution, SolveParams, TimeGrid,
76};
77
78// --- Problem-definition types. ---
79pub use cost::{CostModel, SublevelSet};
80pub use types::{Pseudostate, M, N};
81
82// --- Convex-encoding internals (advanced use; the solve path wraps these). These are reached via
83// their owning modules — `solver::{min_fuel_socp, refine_socp, extract_qp, MinFuelSolution,
84// RefineSolution}` and `types::{ConicRows, Dual, FuelGenerator}` — and are deliberately not
85// re-exported at the crate root, to keep the root surface small. `Dual` is the exception that
86// surfaces in the primary API (it types the re-exported `Solution::lambda` field and the
87// `primer_history` argument); name it as `types::Dual` when you need it. ---
88
89/// Re-export of the [`nalgebra`] version this crate's public API is built on
90/// (`Pseudostate`, `Dual`, `Maneuver::dv`, `Solution::lambda`, `ConicRows`,
91/// `PrimerHistory`). Use `koenig_damico_planner::nalgebra` to construct those
92/// types against a matching version. A `nalgebra` *major* bump is a breaking
93/// change of this crate.
94pub use nalgebra;