1- //! Multi-revolution Lambert throughput (`M = 3`).
1+ //! Multi-revolution Lambert throughput across `M ∈ {1, 3, 5}` plus a
2+ //! Battin near-parabolic regime stress.
3+ //!
4+ //! Two benchmark groups:
5+ //! - `multi_rev`: random Earth-orbit inputs parametrized over the
6+ //! revolution budget via Criterion's `bench_with_input`.
7+ //! - `multi_rev_battin`: a deterministic near-180° geometry whose
8+ //! solutions sit in the Battin regime (`|x − 1| < BATTIN_THRESHOLD`),
9+ //! constructed by jittering TOF around the parabolic time-of-flight.
210//!
311//! Run: `cargo bench --bench multi_rev`.
412
5- use criterion:: { Criterion , criterion_group, criterion_main} ;
6- use lambert_izzo:: { RevolutionBudget , lambert} ;
13+ use criterion:: { BenchmarkId , Criterion , criterion_group, criterion_main} ;
14+ use lambert_izzo:: { LambertInput , RevolutionBudget , TransferWay , lambert} ;
715use lambert_izzo_test_support:: bodies:: MU_EARTH ;
16+ use lambert_izzo_test_support:: elements_u64;
817use lambert_izzo_test_support:: random_inputs:: { Spec , WayStrategy , generate} ;
18+ use rand:: SeedableRng ;
19+ use rand:: distributions:: { Distribution , Uniform } ;
20+ use rand_chacha:: ChaCha20Rng ;
921use std:: hint:: black_box;
1022
1123fn multi_rev_throughput ( c : & mut Criterion ) {
12- let inputs = generate ( & Spec {
13- n : 1_000 ,
14- seed : 0xBEEF_DEAD ,
15- radius_range : ( 5600.0 , 10_500.0 ) ,
16- tof_range : ( 10_000.0 , 250_000.0 ) ,
17- mu : MU_EARTH ,
18- way : WayStrategy :: Short ,
19- revolutions : RevolutionBudget :: try_up_to ( 3 ) . expect ( "3 is within BoundedRevs::MAX" ) ,
20- } ) ;
24+ let mut group = c. benchmark_group ( "multi_rev" ) ;
25+ group. sample_size ( 20 ) ;
26+
27+ for & m in & [ 1u32 , 3 , 5 ] {
28+ let inputs = generate ( & Spec {
29+ n : 1_000 ,
30+ seed : 0xBEEF_DEAD ^ u64:: from ( m) ,
31+ radius_range : ( 5_600.0 , 10_500.0 ) ,
32+ tof_range : ( 10_000.0 , 250_000.0 ) ,
33+ mu : MU_EARTH ,
34+ way : WayStrategy :: Short ,
35+ revolutions : RevolutionBudget :: try_up_to ( m) . expect ( "m ≤ BoundedRevs::MAX" ) ,
36+ } ) ;
37+
38+ group. throughput ( criterion:: Throughput :: Elements ( elements_u64 ( inputs. len ( ) ) ) ) ;
39+ group. bench_with_input ( BenchmarkId :: new ( "M" , m) , & inputs, |b, inputs| {
40+ b. iter ( || {
41+ for input in inputs {
42+ let _ = black_box ( lambert ( input) ) ;
43+ }
44+ } ) ;
45+ } ) ;
46+ }
47+ group. finish ( ) ;
48+ }
2149
22- let mut group = c. benchmark_group ( "multi_rev_M3" ) ;
23- group. throughput ( criterion:: Throughput :: Elements ( inputs. len ( ) as u64 ) ) ;
50+ fn battin_near_parabolic ( c : & mut Criterion ) {
51+ let inputs = generate_battin_inputs ( 1_000 , MU_EARTH ) ;
52+
53+ let mut group = c. benchmark_group ( "multi_rev_battin" ) ;
54+ group. throughput ( criterion:: Throughput :: Elements ( elements_u64 ( inputs. len ( ) ) ) ) ;
2455 group. sample_size ( 20 ) ;
25- group. bench_function ( "lambert_x1000_random_earth " , |b| {
56+ group. bench_function ( "near_parabolic_x1000 " , |b| {
2657 b. iter ( || {
2758 for input in & inputs {
2859 let _ = black_box ( lambert ( input) ) ;
@@ -32,5 +63,38 @@ fn multi_rev_throughput(c: &mut Criterion) {
3263 group. finish ( ) ;
3364}
3465
35- criterion_group ! ( benches, multi_rev_throughput) ;
66+ /// Deterministic batch whose solutions land in `tof.rs`'s Battin regime
67+ /// (`|x − 1| < BATTIN_THRESHOLD = 0.01`). Achieved via a fixed near-180°
68+ /// transfer geometry with TOF jittered around the parabolic time-of-flight
69+ /// (Lancaster's closed form `T_p = (√2 / (3√μ)) · (s^(3/2) − (s−c)^(3/2))`
70+ /// for the short-way branch).
71+ fn generate_battin_inputs ( n : usize , mu : f64 ) -> Vec < LambertInput > {
72+ let r_norm = 7_000.0_f64 ;
73+ // ~177° transfer — close enough to parabolic to land in Battin,
74+ // far enough from 180° to clear `COLINEARITY_TOL = 1e-15`.
75+ let theta = std:: f64:: consts:: PI - 0.05 ;
76+ let r1 = [ r_norm, 0.0 , 0.0 ] ;
77+ let r2 = [ r_norm * theta. cos ( ) , r_norm * theta. sin ( ) , 0.0 ] ;
78+
79+ let dx = r2[ 0 ] - r1[ 0 ] ;
80+ let dy = r2[ 1 ] - r1[ 1 ] ;
81+ let chord = ( dx * dx + dy * dy) . sqrt ( ) ;
82+ let s = ( 2.0 * r_norm + chord) / 2.0 ;
83+ let t_par = ( 2.0 / mu) . sqrt ( ) / 3.0 * ( s. powf ( 1.5 ) - ( s - chord) . powf ( 1.5 ) ) ;
84+
85+ let mut rng = ChaCha20Rng :: seed_from_u64 ( 0xBA77_171F ) ;
86+ let dist = Uniform :: new ( 0.995 * t_par, 1.005 * t_par) ;
87+ ( 0 ..n)
88+ . map ( |_| LambertInput {
89+ r1,
90+ r2,
91+ tof : dist. sample ( & mut rng) ,
92+ mu,
93+ way : TransferWay :: Short ,
94+ revolutions : RevolutionBudget :: SingleOnly ,
95+ } )
96+ . collect ( )
97+ }
98+
99+ criterion_group ! ( benches, multi_rev_throughput, battin_near_parabolic) ;
36100criterion_main ! ( benches) ;
0 commit comments