#![allow(dead_code)]
#![allow(non_snake_case)]
use std::f64::consts::PI;
pub const G: f64 = 6.67430e-11;
pub const M_SUN: f64 = 1.98847e30;
pub const R_SUN: f64 = 6.9634e8;
pub const AU: f64 = 1.495978707e11;
pub const AU_IN_R_SUN: f64 = AU / R_SUN;
pub const GM_SUN: f64 = 1.32712440018e20;
pub const C: f64 = 299792458.0;
pub const K_B: f64 = 1.380649e-23;
pub const STEFAN_BOLTZMANN: f64 = 5.670374419e-8;
pub const MU_0: f64 = 4.0 * PI * 1e-7;
pub const EPSILON_0: f64 = 1.0 / (MU_0 * C * C);
pub const M_PROTON: f64 = 1.67262192369e-27;
pub const M_ELECTRON: f64 = 9.1093837015e-31;
pub const E_CHARGE: f64 = 1.602176634e-19;
pub const T_SUN: f64 = 5778.0;
pub const L_SUN: f64 = 3.828e26;
pub const B_SUN_PHOTOSPHERE: f64 = 2.5;
pub const M_EARTH: f64 = 5.97217e24;
pub const R_EARTH: f64 = 6.371e6;
pub const M_JUPITER: f64 = 1.89813e27;
pub const R_JUPITER: f64 = 7.1492e7;
pub const M_SATURN: f64 = 5.68317e26;
pub const R_SATURN: f64 = 6.0268e7;
pub const M_URANUS: f64 = 8.68103e25;
pub const M_NEPTUNE: f64 = 1.02413e26;
pub const OMEGA_SUN: f64 = 2.865e-6;
#[inline]
pub fn gauss_to_tesla(g: f64) -> f64 {
g * 1e-4
}
#[inline]
pub fn tesla_to_gauss(t: f64) -> f64 {
t * 1e4
}
#[inline]
pub fn au_to_meters(au: f64) -> f64 {
au * AU
}
#[inline]
pub fn meters_to_au(m: f64) -> f64 {
m / AU
}
#[inline]
pub fn r_sun_to_meters(r: f64) -> f64 {
r * R_SUN
}
#[inline]
pub fn meters_to_r_sun(m: f64) -> f64 {
m / R_SUN
}
#[inline]
pub fn deg_to_rad(deg: f64) -> f64 {
deg * PI / 180.0
}
#[inline]
pub fn rad_to_deg(rad: f64) -> f64 {
rad * 180.0 / PI
}
#[inline]
pub fn m_earth_to_kg(m_earth: f64) -> f64 {
m_earth * M_EARTH
}
#[inline]
pub fn kg_to_m_earth(kg: f64) -> f64 {
kg / M_EARTH
}
#[inline]
pub fn year_to_seconds(yr: f64) -> f64 {
yr * 365.25 * 86400.0
}
#[inline]
pub fn seconds_to_year(s: f64) -> f64 {
s / (365.25 * 86400.0)
}
#[inline]
pub fn day_to_seconds(d: f64) -> f64 {
d * 86400.0
}
#[inline]
pub fn seconds_to_day(s: f64) -> f64 {
s / 86400.0
}
#[inline]
pub fn light_year_to_au(ly: f64) -> f64 {
ly * 63241.0
}
pub struct Zone01 {
pub coronal_base_density_cm3: f64,
pub coronal_base_density_m3: f64,
pub alfven_surface_density_cm3: f64,
pub alfven_surface_density_m3: f64,
pub B_photosphere: f64,
pub B_alfven: f64,
pub solar_wind_velocity: f64,
pub n_sw_1au: f64,
}
impl Default for Zone01 {
fn default() -> Self {
Self {
coronal_base_density_cm3: 1.86e6,
coronal_base_density_m3: 1.86e12, alfven_surface_density_cm3: 5e2,
alfven_surface_density_m3: 5e8,
B_photosphere: gauss_to_tesla(2.5),
B_alfven: gauss_to_tesla(5e-3),
solar_wind_velocity: 400.0,
n_sw_1au: 7.0,
}
}
}
impl Zone01 {
pub fn alfven_velocity(B: f64, rho: f64) -> f64 {
B / (MU_0 * rho).sqrt()
}
pub fn magnetic_field_radial_decay(B_surface: f64, r: f64) -> f64 {
let r_ss = 2.5 * R_SUN;
const A1: f64 = 1.26; const A2: f64 = 0.55;
if r <= r_ss {
let ratio = R_SUN / r;
B_surface * (A1 * ratio.powi(3) + A2 * ratio.powi(4))
} else {
let ratio_ss = R_SUN / r_ss;
let B_ss = B_surface * (A1 * ratio_ss.powi(3) + A2 * ratio_ss.powi(4));
B_ss * (r_ss / r).powi(2)
}
}
pub fn coronal_electron_density(r: f64) -> f64 {
let ratio = R_SUN / r;
let n_cm3 = 3.3e5 * ratio.powi(2)
+ 4.1e6 * ratio.powi(4)
+ 8.0e7 * ratio.powi(6);
n_cm3 * 1e6 }
pub fn coronal_mass_density(r: f64) -> f64 {
let n_e = Self::coronal_electron_density(r);
let helium_correction = 1.1; n_e * M_PROTON * helium_correction
}
pub fn parker_solar_wind_velocity(
r: f64,
v_final: f64,
r_0: f64,
lambda: f64
) -> f64 {
let x = (r - r_0) / lambda;
if x < -3.0 {
let t = (-3.0_f64).exp();
(1.0 - (t - 1.0)/(t + 1.0)) * v_final * 0.005
} else if x > 3.0 {
v_final
} else {
(1.0 + x.tanh()) * v_final * 0.5
}
}
pub fn corrected_density_with_acceleration(
r: f64,
v_final: f64,
r_0: f64,
lambda: f64
) -> f64 {
let n_lbl = Self::coronal_electron_density(r);
let n_lbl_1au = Self::coronal_electron_density(AU);
let v_r = Self::parker_solar_wind_velocity(r, v_final, r_0, lambda);
let v_r_safe = v_r.max(1.0);
let n_corr = n_lbl * (n_lbl_1au * v_final) / (n_lbl * v_r_safe * (r / AU).powi(2));
let max_correction = 50.0; n_corr.min(n_lbl * max_correction).max(n_lbl * 0.1)
}
pub const PARKER_R_0: f64 = 1.0; pub const PARKER_LAMBDA: f64 = 6.0;
pub fn calibrated_coronal_density(r: f64, density_factor: f64) -> f64 {
let ratio = R_SUN / r;
let n_cm3 = 3.3e5 * ratio.powi(2);
n_cm3 * 1e6 * density_factor }
pub fn density_radial_decay(_rho_0: f64, _r_0: f64, r: f64) -> f64 {
Self::coronal_mass_density(r)
}
pub fn parker_spiral_magnetic_field(B_0: f64, r: f64, theta: f64, v_sw: f64) -> (f64, f64, f64) {
let B_r = B_0 * (R_SUN / r).powi(2);
let parker_angle = Self::parker_spiral_angle(r, theta, v_sw);
let B_phi = -B_r * parker_angle.tan();
let B_total = (B_r.powi(2) + B_phi.powi(2)).sqrt();
(B_r, B_phi, B_total)
}
pub fn parker_spiral_angle(r: f64, theta: f64, v_sw: f64) -> f64 {
(OMEGA_SUN * r * theta.sin() / v_sw).atan()
}
pub fn alfven_velocity_at_r(&self, r_sun: f64) -> (f64, f64) {
let r = r_sun * R_SUN;
let B_r = Self::magnetic_field_radial_decay(self.B_photosphere, r);
let rho_r = Self::coronal_mass_density(r); let v = Self::alfven_velocity(B_r, rho_r);
(v, v / 1000.0)
}
pub fn alfven_surface_distance_parametric(
&self,
v_final: f64,
B_scale: f64,
density_scale: f64
) -> f64 {
let v_final_m = v_final * 1000.0; let B_surface = self.B_photosphere * B_scale;
let r_low = 3.0 * R_SUN;
let r_high = 40.0 * R_SUN;
Self::solve_alfven_radius_calibrated(
v_final_m,
B_surface,
density_scale,
r_low,
r_high
) / R_SUN
}
fn solve_alfven_radius_calibrated(
v_final: f64,
B_surface: f64,
density_scale: f64,
r_low: f64,
r_high: f64
) -> f64 {
let mut r_lo = r_low;
let mut r_hi = r_high;
let r_0 = Self::PARKER_R_0 * R_SUN;
let lambda_param = Self::PARKER_LAMBDA * R_SUN;
for _ in 0..300 {
let r_mid = (r_lo + r_hi) / 2.0;
let B_mid = Self::magnetic_field_radial_decay(B_surface, r_mid);
let v_sw_mid = Self::parker_solar_wind_velocity(
r_mid, v_final, r_0, lambda_param
);
let n_mid = Self::coronal_electron_density(r_mid) * density_scale;
let rho_mid = n_mid * M_PROTON * 1.1;
let v_a_mid = Self::alfven_velocity(B_mid, rho_mid);
if (v_sw_mid - v_a_mid).abs() < 1.0 {
return r_mid;
}
if v_sw_mid < v_a_mid {
r_lo = r_mid;
} else {
r_hi = r_mid;
}
}
(r_lo + r_hi) / 2.0
}
pub fn alfven_surface_minimum(&self) -> f64 {
self.alfven_surface_distance_parametric(600.0, 0.75, 0.30)
}
pub fn alfven_surface_ascending(&self) -> f64 {
self.alfven_surface_distance_parametric(500.0, 0.90, 0.25)
}
pub fn alfven_surface_maximum(&self) -> f64 {
self.alfven_surface_distance_parametric(400.0, 1.20, 1.00)
}
pub fn alfven_surface_au(&self) -> (f64, f64) {
let r_min = self.alfven_surface_minimum();
let r_max = self.alfven_surface_maximum();
(r_min / AU_IN_R_SUN, r_max / AU_IN_R_SUN)
}
pub fn alfven_surface_range(&self) -> (f64, f64, f64) {
(
self.alfven_surface_minimum(),
self.alfven_surface_ascending(),
self.alfven_surface_maximum(),
)
}
}
#[derive(Debug, Clone, Copy)]
pub enum PlanetType {
Terrestrial,
GasGiant,
IceGiant,
}
#[derive(Debug, Clone)]
pub struct Planet {
pub name: &'static str,
pub planet_type: PlanetType,
pub a_au: f64,
pub a_m: f64,
pub e: f64,
pub inclination_deg: f64,
pub orbital_period_yr: f64,
pub radius_km: f64,
pub radius_m: f64,
pub mass_kg: f64,
pub mass_m_earth: f64,
pub surface_gravity: f64,
pub rotation_period_d: f64,
pub surface_pressure_pa: f64,
pub B_equatorial: f64,
}
pub struct Zone02;
impl Zone02 {
pub fn kepler_third_law(GM: f64, a: f64) -> f64 {
2.0 * PI * (a.powi(3) / GM).sqrt()
}
pub fn kepler_third_law_inverse(GM: f64, T: f64) -> f64 {
(GM * T.powi(2) / (4.0 * PI * PI)).cbrt()
}
pub fn vis_viva(GM: f64, r: f64, a: f64) -> f64 {
(GM * (2.0/r - 1.0/a)).sqrt()
}
pub fn circular_orbit_velocity(GM: f64, r: f64) -> f64 {
(GM / r).sqrt()
}
pub fn escape_velocity(GM: f64, r: f64) -> f64 {
(2.0 * GM / r).sqrt()
}
pub fn perihelion(a: f64, e: f64) -> f64 {
a * (1.0 - e)
}
pub fn aphelion(a: f64, e: f64) -> f64 {
a * (1.0 + e)
}
pub fn eccentricity_vector_3d(
GM: f64,
r_vec: (f64, f64, f64),
v_vec: (f64, f64, f64)
) -> (f64, f64, f64) {
let (rx, ry, rz) = r_vec;
let (vx, vy, vz) = v_vec;
let r = (rx*rx + ry*ry + rz*rz).sqrt();
let hx = ry * vz - rz * vy;
let hy = rz * vx - rx * vz;
let hz = rx * vy - ry * vx;
let vxhx = vy * hz - vz * hy;
let vxhy = vz * hx - vx * hz;
let vxhz = vx * hy - vy * hx;
let ex = vxhx / GM - rx / r;
let ey = vxhy / GM - ry / r;
let ez = vxhz / GM - rz / r;
(ex, ey, ez)
}
pub fn eccentricity_magnitude(
GM: f64,
r_vec: (f64, f64, f64),
v_vec: (f64, f64, f64)
) -> f64 {
let (ex, ey, ez) = Self::eccentricity_vector_3d(GM, r_vec, v_vec);
(ex*ex + ey*ey + ez*ez).sqrt()
}
pub fn hill_radius(a: f64, M: f64, M_central: f64) -> f64 {
a * (M / (3.0 * M_central)).cbrt()
}
pub fn sphere_of_influence(a: f64, m: f64, M_central: f64) -> f64 {
a * (m / M_central).powf(2.0/5.0)
}
pub fn gravity_assist_delta_v(
v_inf: f64,
planet_velocity: f64,
closest_approach: f64,
planet_radius: f64,
planet_GM: f64
) -> f64 {
let r_p = closest_approach.max(planet_radius);
let sin_half_theta = 1.0 / (1.0 + (2.0 * planet_GM) / (r_p * v_inf * v_inf)).sqrt();
2.0 * v_inf * sin_half_theta + planet_velocity
}
pub fn synodic_period(T_inner: f64, T_outer: f64) -> f64 {
(T_inner * T_outer) / (T_outer - T_inner).abs()
}
pub fn earth() -> Planet {
Planet {
name: "Earth",
planet_type: PlanetType::Terrestrial,
a_au: 1.0,
a_m: AU,
e: 0.0167,
inclination_deg: 0.00005,
orbital_period_yr: 1.000017421,
radius_km: 6371.0,
radius_m: 6371.0e3,
mass_kg: 5.97217e24,
mass_m_earth: 1.0,
surface_gravity: 9.80665,
rotation_period_d: 0.99726968,
surface_pressure_pa: 1.01e5,
B_equatorial: gauss_to_tesla(0.312), }
}
pub fn mercury() -> Planet {
Planet {
name: "Mercury",
planet_type: PlanetType::Terrestrial,
a_au: 0.387,
a_m: 0.387 * AU,
e: 0.2056,
inclination_deg: 7.005,
orbital_period_yr: 0.240846,
radius_km: 2439.7,
radius_m: 2439.7e3,
mass_kg: 3.3011e23,
mass_m_earth: 0.0553,
surface_gravity: 3.7,
rotation_period_d: 58.646,
surface_pressure_pa: 1e-9,
B_equatorial: gauss_to_tesla(0.002), }
}
pub fn venus() -> Planet {
Planet {
name: "Venus",
planet_type: PlanetType::Terrestrial,
a_au: 0.723,
a_m: 0.723 * AU,
e: 0.0067,
inclination_deg: 3.39458,
orbital_period_yr: 0.615197,
radius_km: 6051.8,
radius_m: 6051.8e3,
mass_kg: 4.8675e24,
mass_m_earth: 0.815,
surface_gravity: 8.87,
rotation_period_d: -243.025, surface_pressure_pa: 9.2e6,
B_equatorial: 0.0, }
}
pub fn mars() -> Planet {
Planet {
name: "Mars",
planet_type: PlanetType::Terrestrial,
a_au: 1.524,
a_m: 1.524 * AU,
e: 0.0934,
inclination_deg: 1.849,
orbital_period_yr: 1.88082,
radius_km: 3389.5,
radius_m: 3389.5e3,
mass_kg: 6.4171e23,
mass_m_earth: 0.107,
surface_gravity: 3.71,
rotation_period_d: 1.025957,
surface_pressure_pa: 6.0e2,
B_equatorial: gauss_to_tesla(0.0014), }
}
pub fn earth_orbital_velocity() -> (f64, f64) {
let v = Self::circular_orbit_velocity(GM_SUN, AU);
(v, v / 1000.0)
}
pub fn planet_orbital_velocity(planet: &Planet) -> (f64, f64) {
let v = Self::circular_orbit_velocity(GM_SUN, planet.a_m);
(v, v / 1000.0)
}
pub fn solar_constant_at_distance(r_au: f64, S_0: f64) -> f64 {
S_0 * (1.0 / r_au).powi(2)
}
pub const SOLAR_CONSTANT: f64 = 1361.0; }
#[derive(Debug, Clone)]
pub struct KirkwoodResonance {
pub name: &'static str,
pub period_ratio_body_to_planet: f64,
pub position_au: f64,
}
pub struct Zone03;
impl Zone03 {
pub fn resonance_position(a_planet: f64, period_ratio_body_to_planet: f64) -> f64 {
a_planet * period_ratio_body_to_planet.powf(2.0/3.0)
}
pub fn main_resonances() -> Vec<KirkwoodResonance> {
let a_jup = 5.203;
vec![
KirkwoodResonance {
name: "4:1",
period_ratio_body_to_planet: 1.0/4.0,
position_au: Self::resonance_position(a_jup, 1.0/4.0)
},
KirkwoodResonance {
name: "3:1",
period_ratio_body_to_planet: 1.0/3.0,
position_au: Self::resonance_position(a_jup, 1.0/3.0)
},
KirkwoodResonance {
name: "5:2",
period_ratio_body_to_planet: 2.0/5.0,
position_au: Self::resonance_position(a_jup, 2.0/5.0)
},
KirkwoodResonance {
name: "7:3",
period_ratio_body_to_planet: 3.0/7.0,
position_au: Self::resonance_position(a_jup, 3.0/7.0)
},
KirkwoodResonance {
name: "2:1",
period_ratio_body_to_planet: 1.0/2.0,
position_au: Self::resonance_position(a_jup, 1.0/2.0)
},
KirkwoodResonance {
name: "3:2 (Hilda)",
period_ratio_body_to_planet: 2.0/3.0,
position_au: Self::resonance_position(a_jup, 2.0/3.0)
},
]
}
pub fn tisserand_parameter(
a_jupiter: f64,
a: f64,
e: f64,
inclination_rad: f64
) -> f64 {
let i = inclination_rad;
let sqrt_term = (a / a_jupiter * (1.0 - e.powi(2))).sqrt();
a_jupiter / a + 2.0 * sqrt_term * i.cos()
}
pub fn main_belt_boundaries() -> (f64, f64) {
(2.7, 3.6)
}
pub fn main_belt_mass() -> f64 {
let m_moon = 7.342e22; 0.04 * m_moon
}
pub fn is_in_main_belt(a_au: f64) -> bool {
let (inner, outer) = Self::main_belt_boundaries();
a_au >= inner && a_au <= outer
}
}
pub struct Zone04;
impl Zone04 {
pub fn jupiter() -> Planet {
Planet {
name: "Jupiter",
planet_type: PlanetType::GasGiant,
a_au: 5.203,
a_m: 5.203 * AU,
e: 0.0489,
inclination_deg: 1.303,
orbital_period_yr: 11.862,
radius_km: 71492.0,
radius_m: 71492.0e3,
mass_kg: 1.89813e27,
mass_m_earth: 317.8,
surface_gravity: 24.79,
rotation_period_d: 0.41354,
surface_pressure_pa: f64::INFINITY, B_equatorial: gauss_to_tesla(4.28), }
}
pub fn saturn() -> Planet {
Planet {
name: "Saturn",
planet_type: PlanetType::GasGiant,
a_au: 9.537,
a_m: 9.537 * AU,
e: 0.0565,
inclination_deg: 2.485,
orbital_period_yr: 29.457,
radius_km: 60268.0,
radius_m: 60268.0e3,
mass_kg: 5.68317e26,
mass_m_earth: 95.2,
surface_gravity: 10.44,
rotation_period_d: 0.44401,
surface_pressure_pa: f64::INFINITY,
B_equatorial: gauss_to_tesla(0.214), }
}
pub fn uranus() -> Planet {
Planet {
name: "Uranus",
planet_type: PlanetType::IceGiant,
a_au: 19.19,
a_m: 19.19 * AU,
e: 0.0463,
inclination_deg: 0.773,
orbital_period_yr: 84.011,
radius_km: 25559.0,
radius_m: 25559.0e3,
mass_kg: 8.68103e25,
mass_m_earth: 14.5,
surface_gravity: 8.87,
rotation_period_d: -0.71833,
surface_pressure_pa: f64::INFINITY,
B_equatorial: gauss_to_tesla(0.228), }
}
pub fn neptune() -> Planet {
Planet {
name: "Neptune",
planet_type: PlanetType::IceGiant,
a_au: 30.07,
a_m: 30.07 * AU,
e: 0.0095,
inclination_deg: 1.770,
orbital_period_yr: 164.8,
radius_km: 24764.0,
radius_m: 24764.0e3,
mass_kg: 1.02413e26,
mass_m_earth: 17.1,
surface_gravity: 11.15,
rotation_period_d: 0.67125,
surface_pressure_pa: f64::INFINITY,
B_equatorial: gauss_to_tesla(0.142), }
}
pub fn laplace_resonance_check() -> (f64, f64) {
let m_io = Self::io_orbital_period();
let m_europa = Self::europa_orbital_period();
let m_ganymede = Self::ganymede_orbital_period();
(m_europa / m_io, m_ganymede / m_europa)
}
pub fn io_orbital_period() -> f64 {
let GM_jup = G * M_JUPITER;
let a_io = 421800.0e3; Zone02::kepler_third_law(GM_jup, a_io) / 86400.0
}
pub fn europa_orbital_period() -> f64 {
let GM_jup = G * M_JUPITER;
let a_europa = 671034.0e3; Zone02::kepler_third_law(GM_jup, a_europa) / 86400.0
}
pub fn ganymede_orbital_period() -> f64 {
let GM_jup = G * M_JUPITER;
let a_ganymede = 1070412.0e3; Zone02::kepler_third_law(GM_jup, a_ganymede) / 86400.0
}
pub fn neptune_pluto_resonance() -> f64 {
let a_neptune = 30.07 * AU;
let a_pluto = 39.48 * AU;
(a_pluto / a_neptune).powf(3.0/2.0)
}
pub fn giant_planet_hill_radius(planet: &Planet) -> f64 {
Zone02::hill_radius(planet.a_m, planet.mass_kg, M_SUN)
}
pub fn magnetosphere_standoff_chapman_ferraro(
R_planet: f64,
B_surface: f64,
n_sw: f64,
v_sw: f64
) -> f64 {
let rho_sw = n_sw * M_PROTON;
let P_sw = rho_sw * v_sw * v_sw;
let r_ss = R_planet * (B_surface.powi(2) / (2.0 * MU_0 * P_sw)).powf(1.0/6.0);
r_ss
}
pub fn magnetosphere_standoff_at_planet(
planet: &Planet,
r_planet_au: f64,
v_sw: f64
) -> (f64, f64) {
let n_sw_1au = 7.0e6; let n_sw = n_sw_1au * (1.0_f64 / r_planet_au).powi(2);
let v_sw_ms = v_sw * 1000.0;
let r_ss = Self::magnetosphere_standoff_chapman_ferraro(
planet.radius_m,
planet.B_equatorial,
n_sw,
v_sw_ms
);
(r_ss, r_ss / planet.radius_m)
}
pub fn magnetosphere_standoff_full(
_R_planet: f64,
B_equatorial: f64,
n_sw: f64,
v_sw: f64,
rotation_period_s: f64,
is_jupiter: bool
) -> f64 {
let P_sw = n_sw * M_PROTON * v_sw * v_sw;
let omega = 2.0 * PI / rotation_period_s;
let r_min;
let r_max;
if is_jupiter {
r_min = 15.0 * R_JUPITER;
r_max = 80.0 * R_JUPITER;
} else {
r_min = 15.0 * R_SATURN;
r_max = 45.0 * R_SATURN;
}
let mut r_lo = r_min;
let mut r_hi = r_max;
for _ in 0..200 {
let r_mid = (r_lo + r_hi) / 2.0;
let r_rj = r_mid / R_JUPITER;
let r_rs = r_mid / R_SATURN;
let P_internal = if is_jupiter {
MagnetosphericPressure::jupiter_at(r_rj, omega).P_total
} else {
MagnetosphericPressure::saturn_at_with_B(r_rs, omega, B_equatorial).P_total
};
if (P_internal - P_sw).abs() / P_sw < 1e-6 {
return r_mid;
}
if P_internal > P_sw {
r_lo = r_mid;
} else {
r_hi = r_mid;
}
}
(r_lo + r_hi) / 2.0
}
pub fn jupiter_magnetosphere_standoff(n_sw: f64, v_sw: f64) -> f64 {
let rotation_period_jupiter_s = 9.9258 * 3600.0;
Self::magnetosphere_standoff_full(
R_JUPITER,
gauss_to_tesla(4.28),
n_sw,
v_sw,
rotation_period_jupiter_s,
true )
}
pub fn saturn_magnetosphere_standoff(n_sw: f64, v_sw: f64) -> f64 {
let rotation_period_saturn_s = 10.656 * 3600.0;
Self::magnetosphere_standoff_full(
R_SATURN,
gauss_to_tesla(0.214), n_sw,
v_sw,
rotation_period_saturn_s,
false )
}
pub fn magnetosphere_standoff_at_planet_full(
planet: &Planet,
r_planet_au: f64,
v_sw: f64
) -> (f64, f64) {
let n_sw_1au = 7.0e6; let n_sw = n_sw_1au * (1.0_f64 / r_planet_au).powi(2);
let v_sw_ms = v_sw * 1000.0;
let r_ss = match planet.name {
"Jupiter" => Self::jupiter_magnetosphere_standoff(n_sw, v_sw_ms),
"Saturn" => Self::saturn_magnetosphere_standoff(n_sw, v_sw_ms),
_ => Self::magnetosphere_standoff_chapman_ferraro(
planet.radius_m,
planet.B_equatorial,
n_sw,
v_sw_ms
),
};
(r_ss, r_ss / planet.radius_m)
}
}
pub struct JupiterPlasmaModel {
pub n_io_torus: f64,
pub T_io_torus: f64,
pub r_io: f64,
pub source_rate_io: f64,
pub density_decay_index: f64,
pub temperature_decay_index: f64,
pub inner_magnetopause: f64,
pub outer_magnetopause: f64,
}
impl Default for JupiterPlasmaModel {
fn default() -> Self {
Self {
n_io_torus: 2000.0, T_io_torus: 50.0, r_io: 5.9,
source_rate_io: 1000.0,
density_decay_index: 2.5,
temperature_decay_index: 0.5,
inner_magnetopause: 15.0, outer_magnetopause: 50.0, }
}
}
impl JupiterPlasmaModel {
pub fn density_at(&self, r_rj: f64) -> f64 {
if r_rj < 6.0 {
self.n_io_torus * 1e6 * (self.r_io / r_rj).powf(1.0)
} else {
let r6 = r_rj / 6.0;
let n_cm3 = 1987.0 * r6.powf(-8.2) + 14.0 * r6.powf(-3.2) + 0.05 * r6.powf(-0.65);
n_cm3 * 1e6 }
}
pub fn temperature_at(&self, r_rj: f64) -> f64 {
let T_eV = if r_rj < 6.0 {
self.T_io_torus
} else if r_rj < 15.2 {
self.T_io_torus * (r_rj / 6.0).powf(0.8)
} else {
200.0 * (r_rj / 15.2).powf(0.5)
};
T_eV * 11604.525
}
}
pub struct SaturnPlasmaModel {
pub n_enceladus_torus: f64,
pub r_enceladus: f64,
pub n_plasma_sheet: f64,
pub r_plasma_sheet: f64,
pub density_decay_index: f64,
pub T_inner_eV: f64,
pub T_outer_eV: f64,
pub r_T_transition: f64,
}
impl Default for SaturnPlasmaModel {
fn default() -> Self {
Self {
n_enceladus_torus: 100.0, r_enceladus: 4.0, n_plasma_sheet: 0.5, r_plasma_sheet: 6.0, density_decay_index: 3.5, T_inner_eV: 10.0, T_outer_eV: 2000.0, r_T_transition: 8.0, }
}
}
impl SaturnPlasmaModel {
pub fn density_at(&self, r_rs: f64) -> f64 {
if r_rs < self.r_enceladus {
self.n_enceladus_torus * 1e6 * (self.r_enceladus / r_rs).powf(1.0)
} else if r_rs < self.r_plasma_sheet {
let n_cm3 = self.n_enceladus_torus * (self.r_enceladus / r_rs).powf(5.64);
n_cm3 * 1e6
} else {
let r_norm = r_rs / self.r_plasma_sheet;
self.n_plasma_sheet * 1e6 * r_norm.powf(-self.density_decay_index)
}
}
pub fn temperature_at(&self, r_rs: f64) -> f64 {
let T_eV = if r_rs < self.r_T_transition {
self.T_inner_eV
} else {
self.T_inner_eV + (self.T_outer_eV - self.T_inner_eV)
* (1.0 - (-(r_rs - self.r_T_transition) / 10.0_f64).exp())
};
T_eV * 11604.525
}
}
pub struct MagnetosphericPressure {
pub P_magnetic: f64,
pub P_plasma: f64,
pub P_centrifugal: f64,
pub P_total: f64,
pub beta: f64,
}
impl MagnetosphericPressure {
pub fn jupiter_at(r_rj: f64, omega: f64) -> Self {
let r_m = r_rj * R_JUPITER;
let B_equ_tesla = gauss_to_tesla(4.28);
let B_r_tesla = B_equ_tesla * (R_JUPITER / r_m).powi(3);
let P_magnetic = B_r_tesla.powi(2) / (2.0 * MU_0);
let plasma = JupiterPlasmaModel::default();
let n_m3 = plasma.density_at(r_rj);
let T_k = plasma.temperature_at(r_rj);
let P_plasma = n_m3 * K_B * T_k;
let r_hill_rj = 20.0; let omega_eff = omega / (1.0 + (r_rj / r_hill_rj).powi(2));
let m_avg = M_PROTON * 1.5; let rho = n_m3 * m_avg;
let P_centrifugal = rho * omega_eff.powi(2) * r_m.powi(2);
let P_total = P_magnetic + P_plasma + P_centrifugal;
let beta = if P_magnetic > 0.0 { P_plasma / P_magnetic } else { f64::INFINITY };
Self {
P_magnetic,
P_plasma,
P_centrifugal,
P_total,
beta,
}
}
pub fn saturn_at(r_rs: f64, omega: f64) -> Self {
Self::saturn_at_with_B(r_rs, omega, gauss_to_tesla(0.214)) }
pub fn saturn_at_with_B(r_rs: f64, omega: f64, B_equatorial: f64) -> Self {
let r_m = r_rs * R_SATURN;
let B_r_tesla = B_equatorial * (R_SATURN / r_m).powi(3);
let P_magnetic = B_r_tesla.powi(2) / (2.0 * MU_0);
let plasma = SaturnPlasmaModel::default();
let n_m3 = plasma.density_at(r_rs);
let T_k = plasma.temperature_at(r_rs);
let P_plasma = n_m3 * K_B * T_k;
let r_hill_rs = 10.0; let omega_eff = omega / (1.0 + (r_rs / r_hill_rs).powi(2));
let m_avg = M_PROTON * 1.5;
let rho = n_m3 * m_avg;
let P_centrifugal = rho * omega_eff.powi(2) * r_m.powi(2);
let P_total = P_magnetic + P_plasma + P_centrifugal;
let beta = if P_magnetic > 0.0 { P_plasma / P_magnetic } else { f64::INFINITY };
Self {
P_magnetic,
P_plasma,
P_centrifugal,
P_total,
beta,
}
}
}
#[derive(Debug, Clone)]
pub enum TNOClassification {
Plutino,
Cubewano,
ScatteredDisk,
Detached,
ExtremeTNO,
}
pub struct Zone05;
impl Zone05 {
pub fn tno_resonance(a_neptune: f64, period_ratio_body_to_planet: f64) -> f64 {
a_neptune * period_ratio_body_to_planet.powf(2.0/3.0)
}
pub fn neptune_resonances() -> Vec<(&'static str, f64)> {
let a_neptune = 30.07;
vec![
("3:2 (Plutinos)", Self::tno_resonance(a_neptune, 3.0/2.0)),
("5:3", Self::tno_resonance(a_neptune, 5.0/3.0)),
("7:4", Self::tno_resonance(a_neptune, 7.0/4.0)),
("2:1", Self::tno_resonance(a_neptune, 2.0)),
("4:1", Self::tno_resonance(a_neptune, 4.0)),
]
}
pub fn classify_tno(a: f64, e: f64, q: f64) -> TNOClassification {
let Q = a * (1.0 + e);
if a > 150.0 {
TNOClassification::ExtremeTNO
} else if q > 40.0 && Q > 48.0 {
TNOClassification::Detached
} else if e > 0.3 && Q > 50.0 {
TNOClassification::ScatteredDisk
} else if (a - 39.4).abs() < 1.0 {
TNOClassification::Plutino
} else if a >= 42.0 && a <= 48.0 && e < 0.1 {
TNOClassification::Cubewano
} else {
if a < 39.4 {
TNOClassification::Plutino
} else if a < 48.0 {
TNOClassification::Cubewano
} else {
TNOClassification::ScatteredDisk
}
}
}
pub fn kuiper_belt_mass() -> (f64, f64) {
(0.01, 0.1) }
pub fn kuiper_belt_mass_kg() -> (f64, f64) {
let (min, max) = Self::kuiper_belt_mass();
(min * M_EARTH, max * M_EARTH)
}
pub fn kuiper_belt_boundaries() -> (f64, f64, f64) {
(30.0, 50.0, 100.0)
}
}
pub struct SunHillInfo {
pub hill_radius_au: f64,
pub effective_boundary_au: f64,
pub hill_radius_light_years: f64,
pub effective_boundary_light_years: f64,
pub density_low_r_au: f64,
pub density_typ_r_au: f64,
pub density_high_r_au: f64,
pub density_low: f64,
pub density_typ: f64,
pub density_high: f64,
}
pub struct Zone06;
impl Zone06 {
pub fn sun_hill_radius_point_mass(R_galaxy_au: f64, M_enclosed_kg: f64) -> f64 {
R_galaxy_au * (M_SUN / (3.0 * M_enclosed_kg)).cbrt()
}
pub fn sun_tidal_radius_density(rho_galaxy_msun_per_pc3: f64) -> f64 {
let pc_in_m: f64 = 3.0857e16; let rho_si = rho_galaxy_msun_per_pc3 * M_SUN / pc_in_m.powi(3);
let r_m = (M_SUN / (4.0 * PI * rho_si)).cbrt();
r_m / AU }
pub fn sun_hill_radius_range() -> (f64, f64, f64, f64, f64, f64) {
let rho_low = 0.08; let r_low = Self::sun_tidal_radius_density(rho_low);
let rho_typ = 0.10; let r_typ = Self::sun_tidal_radius_density(rho_typ);
let rho_high = 0.30; let r_high = Self::sun_tidal_radius_density(rho_high);
(rho_low, r_low, rho_typ, r_typ, rho_high, r_high)
}
pub fn sun_effective_boundary(rho_galaxy: f64) -> (f64, f64) {
let r_hill = Self::sun_tidal_radius_density(rho_galaxy);
let r_effective = r_hill / 3.0; (r_hill, r_effective)
}
pub fn sun_hill_radius_typical() -> f64 {
let rho_galaxy = 0.1;
Self::sun_tidal_radius_density(rho_galaxy)
}
pub fn sun_hill_radius_info() -> SunHillInfo {
let (rho_low, r_low, rho_typ, r_typ, rho_high, r_high) = Self::sun_hill_radius_range();
let (r_hill, r_eff) = Self::sun_effective_boundary(rho_typ);
SunHillInfo {
hill_radius_au: r_hill,
effective_boundary_au: r_eff,
hill_radius_light_years: r_hill / 63241.0,
effective_boundary_light_years: r_eff / 63241.0,
density_low_r_au: r_low,
density_typ_r_au: r_typ,
density_high_r_au: r_high,
density_low: rho_low,
density_typ: rho_typ,
density_high: rho_high,
}
}
pub fn oort_cloud_theoretical_limit() -> f64 {
200000.0 }
pub fn oort_cloud_boundaries() -> (f64, f64, f64) {
(2000.0, 100000.0, 200000.0)
}
pub fn escape_velocity_at(r_au: f64) -> f64 {
let r_m = r_au * AU;
Zone02::escape_velocity(GM_SUN, r_m)
}
pub fn long_period_comet_period() -> (f64, f64) {
let a_inner_au = 200.0;
let a_outer_au = 20000.0;
let T_inner_s = Zone02::kepler_third_law(GM_SUN, a_inner_au * AU);
let T_outer_s = Zone02::kepler_third_law(GM_SUN, a_outer_au * AU);
let seconds_per_year = 365.25 * 24.0 * 3600.0;
(T_inner_s / seconds_per_year, T_outer_s / seconds_per_year)
}
pub fn perturbation_ratio() -> (f64, f64) {
let f_tidal = 0.70;
let f_stellar = 0.30;
(f_tidal * 100.0, f_stellar * 100.0)
}
}
#[derive(Debug, Clone)]
pub struct VoyagerData {
pub name: &'static str,
pub termination_shock_au: f64,
pub heliopause_au: f64,
pub crossing_date: &'static str,
}
pub struct Zone07;
impl Zone07 {
pub fn voyager1() -> VoyagerData {
VoyagerData {
name: "Voyager 1",
termination_shock_au: 94.0,
heliopause_au: 121.6,
crossing_date: "2012-08-25",
}
}
pub fn voyager2() -> VoyagerData {
VoyagerData {
name: "Voyager 2",
termination_shock_au: 83.7,
heliopause_au: 119.0,
crossing_date: "2018-11-05",
}
}
pub fn lism_parameters() -> (
f64, // 离子密度 (cm⁻³)
f64, // 中性氢密度 (cm⁻³)
f64, // 磁场 (μG)
f64, // ISM流速 (km/s)
f64, // ISM温度 (K)
) {
(0.06, 0.18, 3.2, 26.3, 8000.0)
}
pub fn lism_ion_density_range() -> (f64, f64, f64) {
(0.05, 0.06, 0.12)
}
pub fn solar_wind_dynamic_pressure(n_sw: f64, v_sw: f64) -> f64 {
let rho = n_sw * M_PROTON;
rho * v_sw * v_sw
}
pub fn solar_wind_pressure_1au(n_sw_1au: f64, v_sw: f64) -> f64 {
let n_m3 = n_sw_1au * 1e6; let v_ms = v_sw * 1000.0; Self::solar_wind_dynamic_pressure(n_m3, v_ms)
}
pub fn ism_pressure() -> f64 {
let (n_ion, n_H, B_uG, v_ism_kms, T_ism) = Self::lism_parameters();
let n_total_m3 = (n_ion + n_H) * 1e6; let n_ion_m3 = n_ion * 1e6;
let B_t = B_uG * 1e-10; let v_ism_ms = v_ism_kms * 1000.0;
let P_thermal = n_total_m3 * K_B * T_ism;
let P_magnetic = B_t * B_t / (2.0 * MU_0);
let P_ram = n_ion_m3 * M_PROTON * v_ism_ms * v_ism_ms;
P_thermal + P_magnetic + P_ram
}
pub fn termination_shock_distance(n_sw_1au: f64, v_sw: f64) -> f64 {
let P_sw_1au = Self::solar_wind_pressure_1au(n_sw_1au, v_sw);
let P_ism = Self::ism_pressure();
let v_sw_ms = v_sw * 1000.0;
let T_sw = 1e5; let c_s = (5.0/3.0 * K_B * T_sw / M_PROTON).sqrt(); let mach = v_sw_ms / c_s;
let f_mach = 1.0 - 1.0/(mach * mach);
let r_ts = (P_sw_1au / (P_ism * f_mach)).sqrt();
r_ts * 0.8
}
pub fn heliosheath_total_pressure(r_au: f64, n_sw_1au: f64, v_sw: f64, B_sheath_nT: f64) -> f64 {
let r_ts = Self::termination_shock_distance(n_sw_1au, v_sw);
let P_sw_1au = Self::solar_wind_pressure_1au(n_sw_1au, v_sw);
let P_sw_ts = P_sw_1au / (r_ts * r_ts);
let P_thermal_ts = 0.75 * P_sw_ts;
let alpha: f64 = 0.8;
let P_thermal = P_thermal_ts * (r_ts / r_au).powf(alpha);
let B_t = B_sheath_nT * 1e-9; let P_magnetic = B_t.powi(2) / (2.0 * MU_0);
P_thermal + P_magnetic
}
pub fn heliopause_distance(n_sw_1au: f64, v_sw: f64, B_sheath_nT: f64) -> f64 {
let P_ism = Self::ism_pressure();
let r_low = 80.0; let r_high = 300.0;
let mut r_lo = r_low;
let mut r_hi = r_high;
for _ in 0..200 {
let r_mid = (r_lo + r_hi) / 2.0;
let P_mid = Self::heliosheath_total_pressure(r_mid, n_sw_1au, v_sw, B_sheath_nT);
if (P_mid - P_ism).abs() < 1e-16 {
return r_mid;
}
if P_mid > P_ism {
r_lo = r_mid;
} else {
r_hi = r_mid;
}
}
(r_lo + r_hi) / 2.0
}
pub fn heliosheath_magnetic_field() -> f64 {
let B_r_1au_nT = 3.0; let B_phi_1au_nT = 4.0;
let v_sw = 400.0; let n_sw_1au = 7.0; let r_ts = Self::termination_shock_distance(n_sw_1au, v_sw);
let B_r_ts_nT = B_r_1au_nT / (r_ts * r_ts);
let B_phi_ts_nT = B_phi_1au_nT / r_ts;
let _B_pre_ts_nT = (B_r_ts_nT * B_r_ts_nT + B_phi_ts_nT * B_phi_ts_nT).sqrt();
let B_post_ts_nT = (B_r_ts_nT * B_r_ts_nT + (4.0 * B_phi_ts_nT) * (4.0 * B_phi_ts_nT)).sqrt();
B_post_ts_nT
}
pub fn estimate_boundaries(v_sw: f64, n_sw_1au: f64) -> (f64, f64) {
let r_ts = Self::termination_shock_distance(n_sw_1au, v_sw);
let B_sheath = Self::heliosheath_magnetic_field();
let r_hp = Self::heliopause_distance(n_sw_1au, v_sw, B_sheath);
(r_ts, r_hp)
}
pub fn heliosheath_thickness() -> (f64, f64) {
let r_ts1 = Self::termination_shock_distance(7.0, 400.0);
let B_sh = Self::heliosheath_magnetic_field();
let r_hp1 = Self::heliopause_distance(7.0, 400.0, B_sh);
let thick1 = r_hp1 - r_ts1;
let r_ts2 = Self::termination_shock_distance(5.0, 350.0);
let r_hp2 = Self::heliopause_distance(5.0, 350.0, B_sh);
let thick2 = r_hp2 - r_ts2;
(thick1, thick2)
}
pub fn heliosphere_boundaries() -> (f64, f64) {
let ts_avg = (94.0 + 83.7) / 2.0;
let hp_avg = (121.6 + 119.0) / 2.0;
(ts_avg, hp_avg)
}
}
pub struct SolarCorona;
impl SolarCorona {
pub fn photospheric_flux(T: f64) -> f64 {
STEFAN_BOLTZMANN * T.powi(4)
}
pub fn solar_luminosity(T: f64, R: f64) -> f64 {
4.0 * PI * R.powi(2) * Self::photospheric_flux(T)
}
pub fn solar_luminosity_check() -> (f64, f64, f64) {
let L_calc = Self::solar_luminosity(T_SUN, R_SUN);
let L_iau = L_SUN;
let error = ((L_calc - L_iau) / L_iau * 100.0).abs();
(L_calc, L_iau, error)
}
pub fn magnetic_reconnection_heating() -> (f64, f64) {
let B_corona = 1e-3; let n_corona = 1e15; let L_loop = 1e8; let delta_over_L = 0.05;
let rho_corona = n_corona * M_PROTON * 1.1; let v_A = B_corona / (MU_0 * rho_corona).sqrt();
let _v_inflow = v_A * delta_over_L;
let P_density = B_corona.powi(2) * v_A / (MU_0 * L_loop);
(P_density * 0.3, P_density * 3.0)
}
pub fn alfven_wave_dissipation() -> f64 {
let n_corona = 1e15; let rho_corona = n_corona * M_PROTON * 1.1; let delta_v = 30e3; let v_A = 200e3; let L_damp = 0.5 * R_SUN;
rho_corona * delta_v * delta_v * v_A / L_damp
}
pub fn coronal_temperature() -> (f64, f64) {
let P_min_dyn: f64 = 0.15; let P_max_dyn: f64 = 0.80; let L_cm: f64 = 5e9;
let T_min: f64 = 1.4e3 * (P_min_dyn * L_cm).powf(1.0_f64/3.0);
let T_max: f64 = 1.4e3 * (P_max_dyn * L_cm).powf(1.0_f64/3.0);
(T_min, T_max)
}
}
pub struct IceLine;
impl IceLine {
pub fn physical_ice_line(L_star: f64, T_sub: f64) -> f64 {
Self::physical_ice_line_with_albedo(L_star, T_sub, 0.0)
}
pub fn physical_ice_line_with_albedo(L_star: f64, T_sub: f64, albedo: f64) -> f64 {
let d_m = ((1.0 - albedo) * L_star * L_SUN
/ (16.0 * STEFAN_BOLTZMANN * T_sub.powi(4))).sqrt();
d_m / AU
}
pub fn formation_ice_line(L_star: f64) -> f64 {
const T_REF: f64 = 280.0; const T_ICE: f64 = 170.0;
(T_REF * L_star.powf(0.25) / T_ICE).powi(2)
}
pub fn current_water_ice_line() -> f64 {
Self::physical_ice_line(1.0, 170.0)
}
pub fn co2_ice_line() -> f64 {
Self::physical_ice_line(1.0, 80.0)
}
pub fn co_ice_line() -> f64 {
Self::physical_ice_line(1.0, 22.0)
}
pub fn formation_co2_ice_line(L_star: f64) -> f64 {
const T_REF: f64 = 280.0; const T_CO2: f64 = 80.0;
(T_REF * L_star.powf(0.25) / T_CO2).powi(2)
}
pub fn formation_co_ice_line(L_star: f64) -> f64 {
const T_REF: f64 = 280.0; const T_CO: f64 = 22.0;
(T_REF * L_star.powf(0.25) / T_CO).powi(2)
}
pub fn ice_line_types() -> Vec<(&'static str, f64, f64, &'static str, &'static str)> {
vec![
("形成期水冰线", Self::formation_ice_line(1.0), 170.0, "盘模型 (Hayashi 1981)", "原行星盘内H₂O凝结边界"),
("形成期CO₂冰线", Self::formation_co2_ice_line(1.0), 80.0, "盘模型 (Hayashi 1981)", "原行星盘内CO₂凝结边界"),
("形成期CO冰线", Self::formation_co_ice_line(1.0), 22.0, "盘模型 (Hayashi 1981)", "原行星盘内CO凝结边界"),
("当前水冰线", Self::current_water_ice_line(), 170.0, "真空模型", "当前太阳系H₂O升华平衡"),
("当前CO₂冰线", Self::co2_ice_line(), 80.0, "真空模型", "当前太阳系CO₂升华平衡"),
("当前CO冰线", Self::co_ice_line(), 22.0, "真空模型", "当前太阳系CO升华平衡"),
]
}
pub fn ice_line_for_stellar_luminosity(L: f64) -> f64 {
Self::formation_ice_line(L)
}
}
pub struct HabitableZone;
impl HabitableZone {
pub fn habitable_zone(L: f64, S_eff: f64) -> f64 {
(L / S_eff).sqrt()
}
pub fn solar_habitable_zone() -> (f64, f64) {
let inner = Self::habitable_zone(1.0, 1.107);
let outer = Self::habitable_zone(1.0, 0.356);
(inner, outer)
}
pub const S_EFF_INNER: f64 = 1.107;
pub const S_EFF_OUTER: f64 = 0.356;
}
pub struct Magnetosphere;
impl Magnetosphere {
pub fn gyroradius(m: f64, v_perp: f64, q: f64, B: f64) -> f64 {
m * v_perp / (q.abs() * B)
}
pub fn proton_gyroradius(v_perp: f64, B: f64) -> f64 {
Self::gyroradius(M_PROTON, v_perp, E_CHARGE, B)
}
pub fn electron_gyroradius(v_perp: f64, B: f64) -> f64 {
Self::gyroradius(M_ELECTRON, v_perp, E_CHARGE, B)
}
pub fn lorentz_force(q: f64, v: (f64, f64, f64), B: (f64, f64, f64)) -> (f64, f64, f64) {
let (vx, vy, vz) = v;
let (bx, by, bz) = B;
let fx = vy * bz - vz * by;
let fy = vz * bx - vx * bz;
let fz = vx * by - vy * bx;
(q * fx, q * fy, q * fz)
}
pub fn mirror_force(m: f64, v_perp: f64, B: f64, gradB: f64) -> f64 {
let mu = m * v_perp.powi(2) / (2.0 * B);
-mu * gradB
}
pub fn magnetic_field_gradient(B: f64, r: f64) -> f64 {
-2.0 * B / r
}
}
pub struct Navigation;
impl Navigation {
pub fn light_time_delay(d: f64) -> f64 {
d / C
}
pub fn signal_attenuation(d1: f64, d2: f64, attenuation_1: f64) -> f64 {
attenuation_1 * (d1 / d2).powi(2)
}
pub fn doppler_shift(v: f64, f: f64) -> f64 {
v * f / C
}
pub fn relativistic_doppler_shift(v: f64, f: f64) -> f64 {
let beta = (v / C).abs();
let sign = if v >= 0.0 { 1.0 } else { -1.0 };
if sign >= 0.0 {
f * ((1.0 - beta) / (1.0 + beta)).sqrt()
} else {
f * ((1.0 + beta) / (1.0 - beta)).sqrt()
}
}
pub fn fspl_linear(d: f64, f: f64) -> f64 {
let lambda = C / f;
(4.0 * PI * d / lambda).powi(2)
}
pub fn fspl_db(d: f64, f: f64) -> f64 {
20.0 * (d / 1.0).log10() + 20.0 * (f / 1.0).log10() + 20.0 * (4.0 * PI / C).log10()
}
pub fn planetary_light_delays() -> Vec<(&'static str, f64, f64)> {
vec![
("水星", Self::light_time_delay(0.307 * AU), Self::light_time_delay(0.467 * AU)),
("金星", Self::light_time_delay(0.716 * AU), Self::light_time_delay(0.730 * AU)),
("地球", Self::light_time_delay(0.983 * AU), Self::light_time_delay(1.017 * AU)),
("火星", Self::light_time_delay(1.381 * AU), Self::light_time_delay(1.666 * AU)),
("木星", Self::light_time_delay(4.951 * AU), Self::light_time_delay(5.455 * AU)),
("土星", Self::light_time_delay(8.981 * AU), Self::light_time_delay(10.094 * AU)),
("天王星", Self::light_time_delay(18.83 * AU), Self::light_time_delay(19.55 * AU)),
("海王星", Self::light_time_delay(29.71 * AU), Self::light_time_delay(30.43 * AU)),
]
}
pub fn delay_to_minutes(seconds: f64) -> f64 {
seconds / 60.0
}
}
#[derive(Debug, Clone)]
pub struct StellarType {
pub spectral_type: &'static str,
pub mass_solar: f64,
pub luminosity_solar: f64,
pub hz_inner: f64,
pub hz_outer: f64,
pub ice_line: f64,
pub heliopause_estimate: f64,
}
impl StellarType {
pub fn stellar_types() -> Vec<StellarType> {
vec![
StellarType {
spectral_type: "G2V (类太阳)",
mass_solar: 1.0,
luminosity_solar: 1.0,
hz_inner: HabitableZone::habitable_zone(1.0, HabitableZone::S_EFF_INNER),
hz_outer: HabitableZone::habitable_zone(1.0, HabitableZone::S_EFF_OUTER),
ice_line: IceLine::formation_ice_line(1.0),
heliopause_estimate: 120.0,
},
StellarType {
spectral_type: "K0V",
mass_solar: 0.79,
luminosity_solar: 0.42,
hz_inner: HabitableZone::habitable_zone(0.42, HabitableZone::S_EFF_INNER),
hz_outer: HabitableZone::habitable_zone(0.42, HabitableZone::S_EFF_OUTER),
ice_line: IceLine::formation_ice_line(0.42),
heliopause_estimate: 90.0,
},
StellarType {
spectral_type: "K5V",
mass_solar: 0.67,
luminosity_solar: 0.21,
hz_inner: HabitableZone::habitable_zone(0.21, HabitableZone::S_EFF_INNER),
hz_outer: HabitableZone::habitable_zone(0.21, HabitableZone::S_EFF_OUTER),
ice_line: IceLine::formation_ice_line(0.21),
heliopause_estimate: 70.0,
},
StellarType {
spectral_type: "M0V",
mass_solar: 0.50,
luminosity_solar: 0.07,
hz_inner: HabitableZone::habitable_zone(0.07, HabitableZone::S_EFF_INNER),
hz_outer: HabitableZone::habitable_zone(0.07, HabitableZone::S_EFF_OUTER),
ice_line: IceLine::formation_ice_line(0.07),
heliopause_estimate: 25.0,
},
StellarType {
spectral_type: "M2V",
mass_solar: 0.40,
luminosity_solar: 0.03,
hz_inner: HabitableZone::habitable_zone(0.03, HabitableZone::S_EFF_INNER),
hz_outer: HabitableZone::habitable_zone(0.03, HabitableZone::S_EFF_OUTER),
ice_line: IceLine::formation_ice_line(0.03),
heliopause_estimate: 15.0,
},
StellarType {
spectral_type: "M5V",
mass_solar: 0.15,
luminosity_solar: 0.005,
hz_inner: HabitableZone::habitable_zone(0.005, HabitableZone::S_EFF_INNER),
hz_outer: HabitableZone::habitable_zone(0.005, HabitableZone::S_EFF_OUTER),
ice_line: IceLine::formation_ice_line(0.005),
heliopause_estimate: 5.0,
},
]
}
pub fn radiation_pressure_ratio(luminosity_solar: f64, mass_solar: f64) -> f64 {
luminosity_solar / mass_solar
}
}
pub struct SolarSystemBenchmark;
impl SolarSystemBenchmark {
pub fn print_full_report() {
println!("================================================================================");
println!(" 太阳系全域导航物理边界基准计算系统 v2.0");
println!(" Solar System Holistic Navigation Physical Boundary Benchmark");
println!("================================================================================");
println!("参考标准: CODATA 2018 / IAU 2015 / JPL DE440");
println!("");
Self::print_physical_constants();
Self::print_zone01();
Self::print_zone02();
Self::print_zone03();
Self::print_zone04();
Self::print_zone05();
Self::print_zone06();
Self::print_zone07();
Self::print_stellar_types();
Self::print_navigation_constraints();
}
fn print_physical_constants() {
println!("\n【物理常数基准】");
println!("────────────────────────────────────────────────────────────────────────────────");
println!(" 引力常数 G = {:.6e} m³ kg⁻¹ s⁻² (CODATA 2018)", G);
println!(" 太阳质量 M☉ = {:.6e} kg (IAU 2015)", M_SUN);
println!(" 太阳半径 R☉ = {:.6e} m (IAU 2015)", R_SUN);
println!(" 天文单位 AU = {:.6e} m (IAU 2012)", AU);
println!(" 1 AU in R☉ = {:.4} (计算值)", AU_IN_R_SUN);
println!(" 日心引力常数 = {:.14e} m³ s⁻² (JPL DE440)", GM_SUN);
println!(" 光速 c = {:.0} m s⁻¹ (精确定义)", C);
println!(" 玻尔兹曼 k_B = {:.6e} J K⁻¹ (CODATA 2018)", K_B);
println!(" 斯特藩-玻尔兹曼 = {:.6e} W m⁻² K⁻⁴ (CODATA 2018)", STEFAN_BOLTZMANN);
println!(" 真空磁导率 μ₀ = {:.6e} H m⁻¹ (CODATA 2018)", MU_0);
println!(" 真空介电常数 ε₀ = {:.6e} F m⁻¹ (CODATA 2018)", EPSILON_0);
println!(" 质子质量 m_p = {:.10e} kg (CODATA 2018)", M_PROTON);
println!(" 电子质量 m_e = {:.10e} kg (CODATA 2018)", M_ELECTRON);
println!(" 太阳有效温度 = {:.0} K (IAU 2015)", T_SUN);
println!(" 太阳光度 L☉ = {:.4e} W (IAU 2015)", L_SUN);
println!(" 太阳自转角速度 = {:.3e} rad/s (25.4天周期)", OMEGA_SUN);
}
fn print_zone01() {
let zone01 = Zone01::default();
println!("\n【Zone-01】太阳大气层与阿尔芬面区");
println!("────────────────────────────────────────────────────────────────────────────────");
println!(" 边界: 1 R☉ (光球层) → 10-25 R☉ (阿尔芬面)");
println!("");
let r_min = zone01.alfven_surface_minimum();
let r_asc = zone01.alfven_surface_ascending();
let r_max = zone01.alfven_surface_maximum();
let (au_min, au_max) = zone01.alfven_surface_au();
println!(" [阿尔芬面距离 (PSP校准: Saito磁场+Leblanc密度模型)]");
println!(" 极小期 (冕洞高速风 ~700 km/s): {:.1} R☉ = {:.6} AU", r_min, au_min);
println!(" 上升期 (混合风 ~500 km/s): {:.1} R☉", r_asc);
println!(" 极大期 (慢速风 ~400 km/s): {:.1} R☉ = {:.6} AU", r_max, au_max);
println!(" PSP 2021.04首次穿越: 18.8 R☉ (Kasper et al. 2021)");
println!("");
println!(" [Parker螺旋磁场 (1 AU处,赤道)]");
let v_sw = 400.0 * 1000.0; let (_, _, B_total) = Zone01::parker_spiral_magnetic_field(
zone01.B_photosphere, AU, PI/2.0, v_sw
);
let psi = Zone01::parker_spiral_angle(AU, PI/2.0, v_sw);
println!(" Parker角 ψ ≈ {:.2}°", rad_to_deg(psi));
println!(" 总场强 ≈ {:.2} nT", B_total * 1e9);
println!("");
println!(" [Saito磁场模型 (Saito et al. 1977)]");
let B_saito_1au = Zone01::magnetic_field_radial_decay(zone01.B_photosphere, AU);
println!(" 1 AU处径向场: {:.2} nT (原始Saito系数: A1=1.26, A2=0.55)", B_saito_1au * 1e9);
let n_leblanc_1au = Zone01::coronal_electron_density(AU) * 1e-6;
println!(" 1 AU处电子密度: {:.2} cm⁻³ (Leblanc模型)", n_leblanc_1au);
let (min_h, max_h) = SolarCorona::magnetic_reconnection_heating();
let Q_A = SolarCorona::alfven_wave_dissipation();
let (T_min, T_max) = SolarCorona::coronal_temperature();
println!("");
println!(" [能量输运功率密度 (物理模型)]");
println!(" 光球层辐射: {:.2e} W/m²", SolarCorona::photospheric_flux(T_SUN));
println!(" 磁重联加热: {:.1e} - {:.1e} W/m²", min_h, max_h);
println!(" 阿尔芬波耗散: {:.1e} W/m²", Q_A);
println!(" 日冕温度: {:.1e} - {:.1e} K", T_min, T_max);
}
fn print_zone02() {
println!("\n【Zone-02】内行星带 / 类地行星区");
println!("────────────────────────────────────────────────────────────────────────────────");
println!(" 边界: 0.05 AU (阿尔芬内界) → 2.7 AU (形成期冰雪线)");
println!("");
println!(" [冰线位置]");
let ice_formation = IceLine::formation_ice_line(1.0);
let ice_water = IceLine::current_water_ice_line();
let ice_co2 = IceLine::co2_ice_line();
let ice_co = IceLine::co_ice_line();
println!(" 形成期冰线: {:.2} AU (Hayashi 1981盘模型)", ice_formation);
println!(" 当前水冰线: {:.1} AU (170K, 旋转黑体模型)", ice_water);
println!(" CO₂冰线: {:.1} AU (80K, 旋转黑体模型)", ice_co2);
println!(" CO冰线: {:.1} AU (22K, 旋转黑体模型)", ice_co);
println!("");
println!(" [类地行星轨道参数 + 大气压]");
let earth = Zone02::earth();
println!(" 地球: a={:.3} AU, e={:.4}, P_surface={:.2e} Pa",
earth.a_au, earth.e, earth.surface_pressure_pa);
let mercury = Zone02::mercury();
println!(" 水星: a={:.3} AU, e={:.3}, P_surface={:.2e} Pa",
mercury.a_au, mercury.e, mercury.surface_pressure_pa);
let venus = Zone02::venus();
println!(" 金星: a={:.3} AU, e={:.4}, P_surface={:.2e} Pa",
venus.a_au, venus.e, venus.surface_pressure_pa);
let mars = Zone02::mars();
println!(" 火星: a={:.3} AU, e={:.3}, P_surface={:.2e} Pa",
mars.a_au, mars.e, mars.surface_pressure_pa);
println!("");
println!(" [典型交会周期]");
let T_earth_mars = Zone02::synodic_period(1.0, 1.88);
println!(" 地球-火星: {:.2} 年", T_earth_mars);
let T_earth_venus = Zone02::synodic_period(1.0, 0.615);
println!(" 地球-金星: {:.2} 年", T_earth_venus);
println!("");
println!(" [太阳常数随距离变化]");
println!(" 1 AU (地球): {:.1} W/m²", Zone02::solar_constant_at_distance(1.0, Zone02::SOLAR_CONSTANT));
println!(" 0.387 AU (水星): {:.1} W/m²", Zone02::solar_constant_at_distance(0.387, Zone02::SOLAR_CONSTANT));
println!(" 1.524 AU (火星): {:.1} W/m²", Zone02::solar_constant_at_distance(1.524, Zone02::SOLAR_CONSTANT));
}
fn print_zone03() {
println!("\n【Zone-03】主小行星带");
println!("────────────────────────────────────────────────────────────────────────────────");
println!(" 边界: 2.7 AU (形成期冰线) → 3.6 AU (木星3:1共振)");
println!("");
println!(" [Kirkwood共振位置 (修正period_ratio定义)]");
let resonances = Zone03::main_resonances();
for res in &resonances {
println!(" {} 共振: a={:.3} AU (P_ratio={:.4})",
res.name, res.position_au, res.period_ratio_body_to_planet);
}
let (inner, outer) = Zone03::main_belt_boundaries();
println!("");
println!(" [主带统计]");
println!(" 内边界: {:.1} AU", inner);
println!(" 外边界: {:.1} AU", outer);
println!(" 总质量: {:.2e} kg (~{:.1}% 月球质量)",
Zone03::main_belt_mass(), 4.0);
println!("");
println!(" [Tisserand参数示例 (含偏心率项)]");
let T_asteroid = Zone03::tisserand_parameter(5.203, 2.5, 0.1, deg_to_rad(10.0));
println!(" 主带小行星 (a=2.5 AU, e=0.1, i=10°): T = {:.2}", T_asteroid);
let T_jupiter = Zone03::tisserand_parameter(5.203, 5.203, 0.049, 0.0);
println!(" 木星 (a=5.203 AU, e=0.049, i=1.3°): T = {:.2}", T_jupiter);
}
fn print_zone04() {
println!("\n【Zone-04】巨行星区");
println!("────────────────────────────────────────────────────────────────────────────────");
println!(" 边界: 3.6 AU (主带外缘) → 30 AU (海王星轨道内侧)");
println!("");
println!(" [巨行星磁场与磁层]");
let jupiter = Zone04::jupiter();
let (_r_ss_cf_j, ratio_cf_j) = Zone04::magnetosphere_standoff_at_planet(&jupiter, 5.203, 400.0);
let (_r_ss_full_j, ratio_full_j) = Zone04::magnetosphere_standoff_at_planet_full(&jupiter, 5.203, 400.0);
println!(" 木星:");
println!(" Chapman-Ferraro (纯偶极子): {:.0} R_J", ratio_cf_j);
println!(" 偶极子+等离子体+亚共旋模型: {:.0} R_J", ratio_full_j);
println!(" 注: 纯偶极子模型低估磁盘效应,实际standoff更大");
println!(" Juno实测 (Rutala 2025, JGR):");
println!(" 中值: 71 ± 24 R_J");
println!(" 松弛 (10th percentile): 89 ± 27 R_J");
println!(" 压缩 (90th percentile): 51 ± 23 R_J");
println!(" 历史模型 (Joy 2002, JGR): 63±4 / 92±6 R_J (双模分布)");
let saturn = Zone04::saturn();
let (_r_ss_cf_s, ratio_cf_s) = Zone04::magnetosphere_standoff_at_planet(&saturn, 9.537, 400.0);
let (_r_ss_full_s, ratio_full_s) = Zone04::magnetosphere_standoff_at_planet_full(&saturn, 9.537, 400.0);
println!(" 土星:");
println!(" Chapman-Ferraro (纯偶极子): {:.0} R_S", ratio_cf_s);
println!(" 偶极子+等离子体+亚共旋模型: {:.0} R_S", ratio_full_s);
println!(" Cassini观测: 16-27 R_S (Achilleos 2008双模峰值22/27 R_S; Jackman 2019典型18-25 R_S)");
println!(" Kanani 2010幂律: R₀ ∝ Dp^(-1/5.0±0.8)");
let uranus = Zone04::uranus();
let (_r_ss_ura, ratio_ura) = Zone04::magnetosphere_standoff_at_planet(&uranus, 19.19, 400.0);
println!(" 天王星: B_surface={:.2} G, magnetopause={:.0} R_U (Chapman-Ferraro适用)",
uranus.B_equatorial * 1e4, ratio_ura);
let neptune = Zone04::neptune();
let (_r_ss_nep, ratio_nep) = Zone04::magnetosphere_standoff_at_planet(&neptune, 30.07, 400.0);
println!(" 海王星: B_surface={:.2} G, magnetopause={:.0} R_N (Chapman-Ferraro适用)",
neptune.B_equatorial * 1e4, ratio_nep);
println!("");
println!(" [巨行星希尔球半径]");
println!(" 木星希尔球: {:.2} AU",
Zone02::hill_radius(jupiter.a_m, jupiter.mass_kg, M_SUN) / AU);
println!(" 海王星希尔球: {:.2} AU",
Zone02::hill_radius(neptune.a_m, neptune.mass_kg, M_SUN) / AU);
}
fn print_zone05() {
println!("\n【Zone-05】柯伊伯带与离散盘");
println!("────────────────────────────────────────────────────────────────────────────────");
println!(" 内侧边界: 30 AU (海王星轨道)");
println!(" 主体外缘: 50 AU");
println!(" 离散盘外缘: 100-1,500 AU");
println!("");
println!(" [海王星主要共振 (修正period_ratio)]");
let neptune_res = Zone05::neptune_resonances();
for (name, a) in neptune_res {
println!(" {}: {:.1} AU", name, a);
}
println!("");
println!(" [TNO动力学分类示例]");
let class_pluto = Zone05::classify_tno(39.48, 0.2488, 29.66);
let class_arrokoth = Zone05::classify_tno(44.0, 0.04, 42.0);
let class_sedna = Zone05::classify_tno(552.0, 0.85, 76.0);
println!(" 冥王星 (a=39.48 AU): {:?}", class_pluto);
println!(" Arrokoth (a=44 AU): {:?}", class_arrokoth);
println!(" 塞德娜 (a=552 AU): {:?}", class_sedna);
}
fn print_zone06() {
println!("\n【Zone-06】奥尔特云");
println!("────────────────────────────────────────────────────────────────────────────────");
let (inner, outer, limit) = Zone06::oort_cloud_boundaries();
println!(" 内侧边界: {:.0} AU", inner);
println!(" 主体外缘: {:.0} AU", outer);
println!(" 理论极限: {:.0} AU", limit);
println!("");
let hill_info = Zone06::sun_hill_radius_info();
let (_r_hill, _r_eff) = Zone06::sun_effective_boundary(0.1);
println!(" [太阳在银河系中的Hill球/潮汐半径]");
println!(" 方法: 密度法 r_tidal = (M☉/(4πρ))^(1/3)");
println!(" 典型密度 ρ = 0.10 M☉/pc³ (Eilers et al. 2019)");
println!(" Hill球半径: {:.0} AU ({:.2} 光年)", hill_info.hill_radius_au, hill_info.hill_radius_light_years);
println!(" 动力学稳定边界 (Hill球×1/3): {:.0} AU ({:.2} 光年)", hill_info.effective_boundary_au, hill_info.effective_boundary_light_years);
println!("");
println!(" [不同密度估计对应的潮汐半径]");
println!(" ρ = {:.2} M☉/pc³ → {:.0} AU ({:.2} 光年)",
hill_info.density_low, hill_info.density_low_r_au, hill_info.density_low_r_au / 63241.0);
println!(" ρ = {:.2} M☉/pc³ → {:.0} AU ({:.2} 光年) [典型值]",
hill_info.density_typ, hill_info.density_typ_r_au, hill_info.density_typ_r_au / 63241.0);
println!(" ρ = {:.2} M☉/pc³ → {:.0} AU ({:.2} 光年)",
hill_info.density_high, hill_info.density_high_r_au, hill_info.density_high_r_au / 63241.0);
println!("");
println!(" [说明]");
println!(" 文献引用的1-2光年对应更高密度估计(~0.3-0.5 M☉/pc³)或点质量近似法");
println!(" 奥尔特云外缘(~100,000 AU)接近Hill球1/2,为长期动力学稳定边界");
println!(" 有效引力边界(~60,000 AU≈1光年)对应Hill球1/3,为最严格稳定限制");
println!("");
println!(" [逃逸速度]");
println!(" 1000 AU处: {:.4} m/s", Zone06::escape_velocity_at(1000.0));
println!(" 10000 AU处: {:.4} m/s", Zone06::escape_velocity_at(10000.0));
println!(" 50000 AU处: {:.6} m/s", Zone06::escape_velocity_at(50000.0));
}
fn print_zone07() {
println!("\n【Zone-07】日球层");
println!("────────────────────────────────────────────────────────────────────────────────");
println!(" 日球层是横跨Zone-04至Zone-06的等离子体物理边界");
println!("");
println!(" [Voyager实测边界]");
let v1 = Zone07::voyager1();
let v2 = Zone07::voyager2();
println!(" Voyager 1: 终止激波={:.1} AU, 日球层顶={:.1} AU ({})",
v1.termination_shock_au, v1.heliopause_au, v1.crossing_date);
println!(" Voyager 2: 终止激波={:.1} AU, 日球层顶={:.1} AU ({})",
v2.termination_shock_au, v2.heliopause_au, v2.crossing_date);
let (n_ism, n_h, B_ism, v_ism, T_ism) = Zone07::lism_parameters();
let (v1_n_low, v1_n_typ, v2_n_high) = Zone07::lism_ion_density_range();
println!("");
println!(" [本地星际介质 (LISM) 参数]");
println!(" 离子密度: {:.2} cm⁻³", n_ism);
println!(" (Voyager 1实测: {:.2}-{:.2} cm⁻³, Voyager 2实测: {:.2}-{:.2} cm⁻³)",
v1_n_low, v1_n_typ, v1_n_typ, v2_n_high);
println!(" 中性氢密度: {:.2} cm⁻³ (H/He ≈ 3)", n_h);
println!(" 磁场强度: {:.1} μG (Voyager 1: 2.5-4.5 μG, Voyager 2: 2.0-3.5 μG)", B_ism);
println!(" ISM流速: {:.1} km/s (来流方向 l≈255°, b≈+5°)", v_ism);
println!(" ISM温度: {:.0} K (局部星际云 ~6000-10000 K)", T_ism);
let P_ism = Zone07::ism_pressure();
println!("");
println!(" [压力平衡]");
println!(" LISM总压力: {:.4e} Pa", P_ism);
let (r_ts_est, r_hp_est) = Zone07::estimate_boundaries(400.0, 7.0);
println!(" 终止激波估算(400km/s, 7cm⁻³): {:.1} AU (压力平衡)", r_ts_est);
println!(" 日球层顶估算: {:.1} AU (二分法)", r_hp_est);
}
fn print_stellar_types() {
println!("\n【恒星类型-边界对照表】");
println!("────────────────────────────────────────────────────────────────────────────────");
println!(" 类型 质量(M☉) 光度(L☉) 宜居带(AU) 冰线(AU) 日球层顶(AU)");
println!(" ─────────────────────────────────────────────────────────────────────────────");
for st in StellarType::stellar_types() {
println!(" {:10} {:.2} {:.3} {:.2}-{:.2} {:.2} {:.0}",
st.spectral_type,
st.mass_solar,
st.luminosity_solar,
st.hz_inner,
st.hz_outer,
st.ice_line,
st.heliopause_estimate
);
}
}
fn print_navigation_constraints() {
println!("\n【通信与导航约束】");
println!("────────────────────────────────────────────────────────────────────────────────");
println!(" 目标 光时延迟范围 Doppler频移(±1km/s)");
println!(" ─────────────────────────────────────────────────────────────────────────────");
let delays = Navigation::planetary_light_delays();
let f_carrier = 8.4e9;
for (name, d_min, d_max) in delays {
let t_min = Navigation::delay_to_minutes(d_min);
let t_max = Navigation::delay_to_minutes(d_max);
let doppler = Navigation::doppler_shift(1000.0, f_carrier);
println!(" {:6} {:.2}-{:.2} min {:.2} kHz",
name, t_min, t_max, doppler / 1000.0);
}
println!("");
println!(" [相对论Doppler修正示例 - 低速 (1 km/s)]");
println!(" 注: 在低速(<<c)下,经典与相对论公式差异极小(~10⁻¹²量级, ppt)");
let f_obs_recede = Navigation::relativistic_doppler_shift(1000.0, f_carrier);
let f_obs_approach = Navigation::relativistic_doppler_shift(-1000.0, f_carrier);
let df_classical = Navigation::doppler_shift(1000.0, f_carrier);
let f_classical_recede = f_carrier - df_classical; let f_classical_approach = f_carrier + df_classical; let diff_recede_ppt = ((f_obs_recede - f_classical_recede) / f_carrier).abs() * 1e12;
let diff_approach_ppt = ((f_obs_approach - f_classical_approach) / f_carrier).abs() * 1e12;
println!(" 远离 (+1 km/s): Δf = {:.2} kHz (经典), {:.6} kHz (相对论), 差异 {:.2} ppt",
df_classical / 1000.0, (f_carrier - f_obs_recede) / 1000.0, diff_recede_ppt);
println!(" 接近 (-1 km/s): Δf = {:.2} kHz (经典), {:.6} kHz (相对论), 差异 {:.2} ppt",
df_classical / 1000.0, (f_obs_approach - f_carrier) / 1000.0, diff_approach_ppt);
println!("");
println!(" [相对论Doppler修正示例 - 高速 (100 km/s)]");
println!(" 注: 在较高速度下,相对论修正可观测 (β ≈ 3.3 × 10⁻⁴)");
let v_high = 100_000.0; let f_obs_recede_high = Navigation::relativistic_doppler_shift(v_high, f_carrier);
let f_obs_approach_high = Navigation::relativistic_doppler_shift(-v_high, f_carrier);
let df_classical_high = Navigation::doppler_shift(v_high, f_carrier);
let f_classical_high_recede = f_carrier - df_classical_high;
let f_classical_high_approach = f_carrier + df_classical_high;
let diff_recede_ppb = ((f_obs_recede_high - f_classical_high_recede) / f_carrier).abs() * 1e9;
let diff_approach_ppb = ((f_obs_approach_high - f_classical_high_approach) / f_carrier).abs() * 1e9;
let diff_recede_ppm = diff_recede_ppb / 1000.0;
let diff_approach_ppm = diff_approach_ppb / 1000.0;
println!(" 远离 (+100 km/s): Δf = {:.2} kHz (经典), {:.4} kHz (相对论), 差异 {:.2} ppm ({:.1} ppb)",
df_classical_high / 1000.0, (f_carrier - f_obs_recede_high) / 1000.0,
diff_recede_ppm, diff_recede_ppb);
println!(" 接近 (-100 km/s): Δf = {:.2} kHz (经典), {:.4} kHz (相对论), 差异 {:.2} ppm ({:.1} ppb)",
df_classical_high / 1000.0, (f_obs_approach_high - f_carrier) / 1000.0,
diff_approach_ppm, diff_approach_ppb);
println!(" β = v/c = {:.3e}", v_high / C);
println!("");
println!(" [自由空间路径损耗 (FSPL)]");
let fspl_1au = Navigation::fspl_db(AU, f_carrier);
let fspl_mars = Navigation::fspl_db(1.5 * AU, f_carrier);
let fspl_neptune = Navigation::fspl_db(30.0 * AU, f_carrier);
println!(" 1 AU (X-band 8.4 GHz): {:.1} dB", fspl_1au);
println!(" 1.5 AU (X-band): {:.1} dB", fspl_mars);
println!(" 30 AU (X-band): {:.1} dB", fspl_neptune);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_au_to_meters() {
let au_calc = AU;
assert!((au_calc - 1.495978707e11).abs() < 1e3);
}
#[test]
fn test_au_in_r_sun() {
let ratio = AU / R_SUN;
assert!((ratio - 214.83).abs() < 0.1);
}
#[test]
fn test_magnetic_field_conversion() {
let B_G = 100.0;
let B_T = gauss_to_tesla(B_G);
assert!((B_T - 0.01).abs() < 1e-10);
}
#[test]
fn test_t_sun_value() {
assert!((T_SUN - 5778.0).abs() < 0.1);
}
#[test]
fn test_alfven_velocity() {
let B = 1e-4; let rho = 1e14 * M_PROTON; let v_A = Zone01::alfven_velocity(B, rho);
assert!(v_A > 1e5 && v_A < 1e6);
}
#[test]
fn test_alfven_surface_typical() {
let zone01 = Zone01::default();
let r_min = zone01.alfven_surface_minimum();
let r_max = zone01.alfven_surface_maximum();
let r_asc = zone01.alfven_surface_ascending();
assert!(r_min >= 8.0 && r_min <= 15.0,
"极小期阿尔芬面应在8-15 R☉,实际 {:.1} R☉", r_min);
assert!(r_max >= 14.0 && r_max <= 22.0,
"极大期阿尔芬面应在14-22 R☉,实际 {:.1} R☉", r_max);
assert!(r_asc >= 15.0 && r_asc <= 22.0,
"上升期阿尔芬面应在15-22 R☉,实际 {:.1} R☉", r_asc);
}
#[test]
fn test_parker_spiral_angle() {
let psi = Zone01::parker_spiral_angle(AU, PI/2.0, 400.0 * 1000.0);
assert!(psi > 0.0 && psi < PI/2.0);
}
#[test]
fn test_parker_spiral_magnetic_field() {
let (Br, Bphi, Btotal) = Zone01::parker_spiral_magnetic_field(
gauss_to_tesla(2.5), AU, PI/2.0, 400.0 * 1000.0
);
assert!(Br > 0.0);
assert!(Bphi < 0.0);
assert!(Btotal > Br.abs());
}
#[test]
fn test_kepler_third_law_earth() {
let T = Zone02::kepler_third_law(GM_SUN, AU);
let T_yr = seconds_to_year(T);
assert!((T_yr - 1.0).abs() < 0.01);
}
#[test]
fn test_vis_viva_earth() {
let v = Zone02::vis_viva(GM_SUN, AU, AU);
assert!((v/1000.0 - 29.78).abs() < 0.1);
}
#[test]
fn test_circular_orbit_velocity() {
let v = Zone02::circular_orbit_velocity(GM_SUN, AU);
assert!((v/1000.0 - 29.78).abs() < 0.1);
}
#[test]
fn test_escape_velocity() {
let GM_EARTH = 3.986004418e14; let v_esc = Zone02::escape_velocity(GM_EARTH, R_EARTH);
assert!((v_esc/1000.0 - 11.19).abs() < 0.1);
}
#[test]
fn test_perihelion_aphelion() {
let a = 1.0 * AU;
let e = 0.0167;
let r_peri = Zone02::perihelion(a, e);
let r_aph = Zone02::aphelion(a, e);
assert!((r_peri - 0.9833 * AU).abs() < 0.001 * AU);
assert!((r_aph - 1.0167 * AU).abs() < 0.001 * AU);
}
#[test]
fn test_hill_radius() {
let r_hill = Zone02::hill_radius(AU, M_EARTH, M_SUN);
assert!(r_hill > 1e9 && r_hill < 2e9);
}
#[test]
fn test_sphere_of_influence() {
let r_soi = Zone02::sphere_of_influence(AU, M_EARTH, M_SUN);
assert!(r_soi > 5e8 && r_soi < 3e9);
}
#[test]
fn test_synodic_period() {
let T_syn = Zone02::synodic_period(1.0, 1.88);
assert!((T_syn - 2.14).abs() < 0.1);
}
#[test]
fn test_eccentricity_vector_3d() {
let r_vec = (AU, 0.0, 0.0);
let v_vec = (0.0, 29.78 * 1000.0, 0.0);
let e = Zone02::eccentricity_magnitude(GM_SUN, r_vec, v_vec);
assert!(e < 0.01); }
#[test]
fn test_solar_constant_at_distance() {
let S_1au = Zone02::solar_constant_at_distance(1.0, Zone02::SOLAR_CONSTANT);
assert!((S_1au - 1361.0).abs() < 1.0);
let S_2au = Zone02::solar_constant_at_distance(2.0, Zone02::SOLAR_CONSTANT);
assert!((S_2au - 1361.0/4.0).abs() < 1.0);
}
#[test]
fn test_kirkwood_resonance_3_1_fixed() {
let a_jup = 5.203; let a_3_1 = Zone03::resonance_position(a_jup, 1.0/3.0);
assert!((a_3_1 - 2.50).abs() < 0.01);
}
#[test]
fn test_kirkwood_resonance_2_1_fixed() {
let a_jup = 5.203;
let a_2_1 = Zone03::resonance_position(a_jup, 1.0/2.0);
assert!((a_2_1 - 3.27).abs() < 0.01);
}
#[test]
fn test_kirkwood_resonance_4_1() {
let a_jup = 5.203;
let a_4_1 = Zone03::resonance_position(a_jup, 1.0/4.0);
assert!((a_4_1 - 2.06).abs() < 0.01);
}
#[test]
fn test_kirkwood_resonance_hilda() {
let a_jup = 5.203;
let a_hilda = Zone03::resonance_position(a_jup, 2.0/3.0);
assert!((a_hilda - 3.97).abs() < 0.01);
}
#[test]
fn test_tisserand_parameter_with_eccentricity() {
let a_jup = 5.203;
let T = Zone03::tisserand_parameter(a_jup, 3.0, 0.1, deg_to_rad(10.0));
assert!(T > 2.0 && T < 4.0);
let T_e0 = Zone03::tisserand_parameter(a_jup, 3.0, 0.0, deg_to_rad(10.0));
assert!((T - T_e0).abs() > 0.0); }
#[test]
fn test_main_belt_boundaries() {
let (inner, outer) = Zone03::main_belt_boundaries();
assert!((inner - 2.7).abs() < 0.01);
assert!((outer - 3.6).abs() < 0.01);
}
#[test]
fn test_laplace_resonance() {
let (io_eu, eu_ga) = Zone04::laplace_resonance_check();
assert!((io_eu - 2.0).abs() < 0.1);
assert!((eu_ga - 2.0).abs() < 0.1);
}
#[test]
fn test_neptune_pluto_resonance() {
let ratio = Zone04::neptune_pluto_resonance();
assert!((ratio - 1.5).abs() < 0.1);
}
#[test]
fn test_magnetosphere_standoff_chapman_ferraro() {
let r_ss = Zone04::magnetosphere_standoff_chapman_ferraro(
R_EARTH,
gauss_to_tesla(0.312),
7.0e6, 400.0 * 1000.0 );
assert!(r_ss > 5.0 * R_EARTH && r_ss < 15.0 * R_EARTH);
}
#[test]
fn test_jupiter_magnetosphere_full_model() {
let n_sw_1au = 7.0e6; let r_jupiter_au = 5.203;
let n_sw = n_sw_1au * (1.0_f64 / r_jupiter_au).powi(2);
let v_sw = 400.0 * 1000.0;
let r_ss_jupiter = Zone04::jupiter_magnetosphere_standoff(n_sw, v_sw);
let ratio_j = r_ss_jupiter / R_JUPITER;
assert!(ratio_j > 20.0 && ratio_j < 80.0,
"木星磁层standoff应在20-80 R_J范围,实测 {:.0} R_J", ratio_j);
}
#[test]
fn test_saturn_magnetosphere_full_model() {
let n_sw_1au = 7.0e6;
let r_saturn_au = 9.537;
let n_sw = n_sw_1au * (1.0_f64 / r_saturn_au).powi(2);
let v_sw = 400.0 * 1000.0;
let r_ss_saturn = Zone04::saturn_magnetosphere_standoff(n_sw, v_sw);
let ratio_s = r_ss_saturn / R_SATURN;
assert!(ratio_s > 15.0 && ratio_s < 45.0,
"土星磁层standoff应在15-45 R_S范围,实测 {:.0} R_S", ratio_s);
}
#[test]
fn test_jupiter_plasma_model() {
let plasma = JupiterPlasmaModel::default();
let n_torus = plasma.density_at(5.9) / 1e6; assert!((n_torus - 2000.0).abs() < 100.0);
let n_outer = plasma.density_at(30.0) / 1e6;
assert!(n_outer < 1.0, "外磁层密度应<1 cm⁻³ (BD2011), got {}", n_outer);
assert!(n_outer > 0.001, "外磁层密度应>0.001 cm⁻³ (BD2011), got {}", n_outer);
}
#[test]
fn test_pressure_balance() {
let omega = 2.0 * PI / (9.9258 * 3600.0);
let pressure = MagnetosphericPressure::jupiter_at(50.0, omega);
assert!(pressure.beta > 0.1, "木星磁层β应>0.1");
assert!(pressure.P_plasma > 0.0);
assert!(pressure.P_total > pressure.P_magnetic);
}
#[test]
fn test_neptune_resonance_3_2_fixed() {
let a_neptune = 30.07;
let a_plutinos = Zone05::tno_resonance(a_neptune, 3.0/2.0);
assert!((a_plutinos - 39.4).abs() < 0.1);
}
#[test]
fn test_neptune_resonance_2_1_fixed() {
let a_neptune = 30.07;
let a_2_1 = Zone05::tno_resonance(a_neptune, 2.0);
assert!((a_2_1 - 47.7).abs() < 0.1);
}
#[test]
fn test_tno_classification_plutino() {
let class = Zone05::classify_tno(39.4, 0.2, 30.0);
assert!(matches!(class, TNOClassification::Plutino));
}
#[test]
fn test_tno_classification_cubewano() {
let class = Zone05::classify_tno(44.0, 0.05, 42.0);
assert!(matches!(class, TNOClassification::Cubewano));
}
#[test]
fn test_tno_classification_extreme() {
let class = Zone05::classify_tno(500.0, 0.8, 80.0);
assert!(matches!(class, TNOClassification::ExtremeTNO));
}
#[test]
fn test_oort_cloud_boundaries() {
let (inner, outer, limit) = Zone06::oort_cloud_boundaries();
assert!(inner >= 2000.0 && inner <= 5000.0);
assert!(outer >= 50000.0 && outer <= 100000.0);
assert!((limit - 200000.0).abs() < 100.0);
}
#[test]
fn test_sun_hill_radius_density() {
let r_tidal = Zone06::sun_hill_radius_typical();
assert!(r_tidal > 150000.0 && r_tidal < 250000.0);
let (r_hill, r_eff) = Zone06::sun_effective_boundary(0.1);
assert!((r_hill / r_eff - 3.0).abs() < 0.1);
let (rho_low, r_low, rho_typ, r_typ, rho_high, r_high) = Zone06::sun_hill_radius_range();
assert!(r_low > r_typ && r_typ > r_high); assert!((rho_low - 0.08).abs() < 0.001);
assert!((rho_typ - 0.10).abs() < 0.001);
assert!((rho_high - 0.30).abs() < 0.001);
}
#[test]
fn test_escape_velocity_at_oort() {
let v_esc = Zone06::escape_velocity_at(50000.0);
assert!(v_esc > 100.0 && v_esc < 300.0);
}
#[test]
fn test_perturbation_ratio() {
let (gal, star) = Zone06::perturbation_ratio();
assert!((gal + star - 100.0).abs() < 0.01);
}
#[test]
fn test_voyager_data() {
let v1 = Zone07::voyager1();
let v2 = Zone07::voyager2();
assert!((v1.termination_shock_au - 94.0).abs() < 0.1);
assert!((v1.heliopause_au - 121.6).abs() < 0.1);
assert!((v2.termination_shock_au - 83.7).abs() < 0.1);
assert!((v2.heliopause_au - 119.0).abs() < 0.1);
}
#[test]
fn test_solar_wind_dynamic_pressure() {
let P = Zone07::solar_wind_dynamic_pressure(5e6, 400e3);
assert!(P > 1e-10 && P < 1e-8);
}
#[test]
fn test_ism_pressure() {
let P = Zone07::ism_pressure();
assert!(P > 1e-13 && P < 2e-13);
}
#[test]
fn test_termination_shock_distance() {
let r_ts = Zone07::termination_shock_distance(7.0, 400.0);
assert!(r_ts > 70.0 && r_ts < 110.0);
}
#[test]
fn test_heliopause_distance() {
let B_sheath = Zone07::heliosheath_magnetic_field();
let r_hp = Zone07::heliopause_distance(7.0, 400.0, B_sheath);
assert!(r_hp > 110.0 && r_hp < 145.0);
}
#[test]
fn test_estimate_boundaries() {
let (r_ts, r_hp) = Zone07::estimate_boundaries(400.0, 7.0);
assert!(r_ts > 80.0 && r_ts < 100.0);
assert!(r_hp > 110.0 && r_hp < 145.0);
}
#[test]
fn test_formation_ice_line() {
let d_ice = IceLine::formation_ice_line(1.0);
assert!((d_ice - 2.71).abs() < 0.3);
}
#[test]
fn test_physical_ice_line_water() {
let d_water = IceLine::current_water_ice_line();
assert!((d_water - 4.75).abs() < 0.5);
}
#[test]
fn test_physical_ice_line_co2() {
let d_co2 = IceLine::co2_ice_line();
assert!(d_co2 > 15.0 && d_co2 < 30.0);
}
#[test]
fn test_physical_ice_line_co() {
let d_co = IceLine::co_ice_line();
assert!(d_co > 200.0 && d_co < 400.0);
}
#[test]
fn test_ice_line_types() {
let types = IceLine::ice_line_types();
assert_eq!(types.len(), 6);
assert!((types[0].1 - 2.71).abs() < 0.3);
assert_eq!(types[0].3, "盘模型 (Hayashi 1981)");
assert!((types[1].1 - 12.25).abs() < 1.0);
assert_eq!(types[1].3, "盘模型 (Hayashi 1981)");
assert!((types[2].1 - 162.0).abs() < 20.0);
assert_eq!(types[2].3, "盘模型 (Hayashi 1981)");
assert!((types[3].1 - 4.75).abs() < 0.5);
assert_eq!(types[3].3, "真空模型");
assert!(types[4].1 > 15.0 && types[4].1 < 30.0);
assert_eq!(types[4].3, "真空模型");
assert!(types[5].1 > 200.0 && types[5].1 < 400.0);
assert_eq!(types[5].3, "真空模型");
}
#[test]
fn test_formation_co2_ice_line() {
let d_co2_disk = IceLine::formation_co2_ice_line(1.0);
assert!((d_co2_disk - 12.25).abs() < 1.0);
let d_co2_vac = IceLine::co2_ice_line();
assert!(d_co2_vac > d_co2_disk); }
#[test]
fn test_formation_co_ice_line() {
let d_co_disk = IceLine::formation_co_ice_line(1.0);
assert!((d_co_disk - 162.0).abs() < 20.0);
let d_co_vac = IceLine::co_ice_line();
assert!(d_co_vac > d_co_disk); }
#[test]
fn test_solar_habitable_zone() {
let (inner, outer) = HabitableZone::solar_habitable_zone();
assert!((inner - 0.95).abs() < 0.05);
assert!((outer - 1.67).abs() < 0.1);
}
#[test]
fn test_proton_gyroradius() {
let r_g = Magnetosphere::proton_gyroradius(1e6, 1e-8);
assert!(r_g > 1.0);
}
#[test]
fn test_lorentz_force() {
let F = Magnetosphere::lorentz_force(
E_CHARGE,
(1e6, 0.0, 0.0),
(0.0, 0.0, 1e-5)
);
assert!((F.1 - 1.6e-19 * 1e-5 * 1e6).abs() < 1e-10);
}
#[test]
fn test_light_time_delay() {
let t = Navigation::light_time_delay(AU);
assert!((t - 499.0).abs() < 1.0);
}
#[test]
fn test_doppler_shift() {
let df = Navigation::doppler_shift(1000.0, 8.4e9);
assert!((df / 1000.0 - 28.0).abs() < 1.0);
}
#[test]
fn test_relativistic_doppler_shift() {
let f_obs = Navigation::relativistic_doppler_shift(1000.0, 1.0e9);
let f_obs_classical = 1.0e9 + Navigation::doppler_shift(1000.0, 1.0e9);
assert!(f_obs < f_obs_classical);
let f_obs_blue = Navigation::relativistic_doppler_shift(-1000.0, 1.0e9);
assert!(f_obs_blue > 1.0e9);
}
#[test]
fn test_fspl_linear() {
let fspl = Navigation::fspl_linear(1e11, 1e10); let fspl_db = 10.0 * fspl.log10();
assert!(fspl_db > 265.0 && fspl_db < 280.0);
}
#[test]
fn test_fspl_db() {
let fspl = Navigation::fspl_db(AU, 8.4e9); assert!(fspl > 270.0 && fspl < 280.0);
}
#[test]
fn test_solar_luminosity() {
let (calc, iau, err) = SolarCorona::solar_luminosity_check();
assert!((calc - iau).abs() < iau * 0.05);
assert!(err < 5.0);
}
#[test]
fn test_photospheric_flux() {
let flux = SolarCorona::photospheric_flux(5778.0);
assert!((flux - 6.3e7).abs() < 1e6);
}
#[test]
fn test_deg_to_rad() {
let rad = deg_to_rad(180.0);
assert!((rad - PI).abs() < 1e-10);
}
#[test]
fn test_rad_to_deg() {
let deg = rad_to_deg(PI);
assert!((deg - 180.0).abs() < 1e-10);
}
#[test]
fn test_year_to_seconds() {
let s = year_to_seconds(1.0);
assert!((s - 3.15576e7).abs() < 1e5);
}
#[test]
fn test_light_year_to_au() {
let au = light_year_to_au(1.0);
assert!((au - 63241.0).abs() < 1.0);
}
#[test]
fn test_stellar_types_count() {
let types = StellarType::stellar_types();
assert_eq!(types.len(), 6);
}
#[test]
fn test_radiation_pressure_ratio() {
let eps = StellarType::radiation_pressure_ratio(1.0, 1.0);
assert!((eps - 1.0).abs() < 0.01);
}
#[test]
fn test_planet_atmospheric_pressure() {
let earth = Zone02::earth();
assert!((earth.surface_pressure_pa - 1.01e5).abs() < 1e3);
let venus = Zone02::venus();
assert!((venus.surface_pressure_pa - 9.2e6).abs() < 1e5);
let mars = Zone02::mars();
assert!((mars.surface_pressure_pa - 6.0e2).abs() < 10.0);
}
#[test]
fn test_planet_magnetic_field() {
let earth = Zone02::earth();
assert!((earth.B_equatorial * 1e4 - 0.312).abs() < 0.01);
let jupiter = Zone04::jupiter();
assert!((jupiter.B_equatorial * 1e4 - 4.28).abs() < 0.1);
}
#[test]
fn test_full_numerical_output() {
println!("");
println!("╔══════════════════════════════════════════════════════════════════════════════╗");
println!("║ 太阳系全域导航物理边界基准 — 精确数值输出 ║");
println!("╚══════════════════════════════════════════════════════════════════════════════╝");
println!("\n【基础物理常数】");
println!(" AU/R☉ = {:.4}", AU / R_SUN);
println!(" GM☉ = {:.14e} m³/s²", GM_SUN);
println!(" T☉ = {:.1} K", T_SUN);
println!(" L☉ = {:.6e} W", L_SUN);
let zone01 = Zone01::default();
println!("\n【Zone-01】太阳大气层与阿尔芬面区");
println!(" B_photosphere = {:.6e} T ({:.2} G)", zone01.B_photosphere, zone01.B_photosphere*1e4);
let n_leblanc_rsun = Zone01::coronal_electron_density(R_SUN);
println!(" n_corona_base = {:.4e} m⁻³ (Leblanc模型)", n_leblanc_rsun);
let r_min_rs = zone01.alfven_surface_minimum();
let r_asc_rs = zone01.alfven_surface_ascending();
let r_max_rs = zone01.alfven_surface_maximum();
let (au_min, au_max) = zone01.alfven_surface_au();
println!(" 阿尔芬面(极小期 700km/s) = {:.2} R☉ = {:.6} AU", r_min_rs, au_min);
println!(" 阿尔芬面(上升期 500km/s) = {:.2} R☉", r_asc_rs);
println!(" 阿尔芬面(极大期 400km/s) = {:.2} R☉ = {:.6} AU", r_max_rs, au_max);
let v_sw_m = 400e3;
let (Br, Bphi, Bt) = Zone01::parker_spiral_magnetic_field(zone01.B_photosphere, AU, PI/2.0, v_sw_m);
let psi = Zone01::parker_spiral_angle(AU, PI/2.0, v_sw_m);
println!(" Parker螺旋@1AU: B_r={:.4e} T, B_φ={:.4e} T, B_total={:.4e} T ({:.2} nT)", Br, Bphi, Bt, Bt*1e9);
println!(" Parker角 ψ = {:.2}°", rad_to_deg(psi));
let B_saito_1au = Zone01::magnetic_field_radial_decay(zone01.B_photosphere, AU);
println!(" Saito模型@1AU: B_r={:.4e} T ({:.2} nT)", B_saito_1au, B_saito_1au*1e9);
println!("\n【Zone-02】内行星带");
let v_esc_earth = Zone02::escape_velocity(3.986004418e14, R_EARTH);
let v_circ_earth = Zone02::circular_orbit_velocity(GM_SUN, AU);
let v_esc_sun_1au = Zone02::escape_velocity(GM_SUN, AU);
println!(" 地球表面逃逸速度 = {:.4} m/s ({:.2} km/s)", v_esc_earth, v_esc_earth/1000.0);
println!(" 1AU圆轨道速度 = {:.4} m/s ({:.2} km/s)", v_circ_earth, v_circ_earth/1000.0);
println!(" 1AU太阳逃逸速度 = {:.4} m/s ({:.2} km/s)", v_esc_sun_1au, v_esc_sun_1au/1000.0);
println!(" 希尔球(地球) = {:.4e} m = {:.6} AU", Zone02::hill_radius(AU, M_EARTH, M_SUN), Zone02::hill_radius(AU, M_EARTH, M_SUN)/AU);
println!(" SOI(地球) = {:.4e} m = {:.6} AU", Zone02::sphere_of_influence(AU, M_EARTH, M_SUN), Zone02::sphere_of_influence(AU, M_EARTH, M_SUN)/AU);
println!(" 交会周期(地-火) = {:.2} 天", Zone02::synodic_period(365.25, 687.0));
println!("\n【Zone-03】主小行星带");
let kirkwood_31 = Zone03::resonance_position(5.203, 1.0/4.0);
let kirkwood_21 = Zone03::resonance_position(5.203, 1.0/3.0);
let kirkwood_52 = Zone03::resonance_position(5.203, 2.0/5.0);
println!(" Kirkwood 3:1 = {:.4} AU", kirkwood_31);
println!(" Kirkwood 2:1 = {:.4} AU", kirkwood_21);
println!(" Kirkwood 5:2 = {:.4} AU", kirkwood_52);
println!("\n【Zone-04】巨行星区");
let jupiter = Zone04::jupiter();
let (_r_ss_j, ratio_j) = Zone04::magnetosphere_standoff_at_planet(&jupiter, 5.203, 400.0);
let (_r_ss_j_full, ratio_j_full) = Zone04::magnetosphere_standoff_at_planet_full(&jupiter, 5.203, 400.0);
println!(" 木星:");
println!(" Chapman-Ferraro: {:.1} R_J", ratio_j);
println!(" 偶极子+等离子体+亚共旋: {:.0} R_J", ratio_j_full);
println!(" Juno实测: 71 ± 24 R_J (Rutala 2025)");
let _neptune = Zone04::neptune();
let nep_32 = Zone05::tno_resonance(30.07, 3.0/2.0);
println!(" 海王星3:2共振 = {:.2} AU", nep_32);
let tisserand = Zone03::tisserand_parameter(5.203, 3.0, 0.05, 0.0_f64.to_radians());
println!(" Tisserand参数(3AU, e=0.05, i=0°) = {:.4}", tisserand);
println!("\n【Zone-05】柯伊伯带");
let plutino_32 = Zone05::tno_resonance(30.07, 2.0/3.0);
println!(" 冥族小天体(2:3共振) = {:.2} AU", plutino_32);
println!("\n【Zone-06】奥尔特云");
let v_esc_10k = Zone06::escape_velocity_at(10000.0);
let v_esc_50k = Zone06::escape_velocity_at(50000.0);
println!(" 逃逸速度@10000 AU = {:.4} m/s", v_esc_10k);
println!(" 逃逸速度@50000 AU = {:.4} m/s", v_esc_50k);
let r_tidal = Zone06::sun_tidal_radius_density(0.1);
println!(" 太阳潮汐半径(ρ=0.1 M☉/pc³) = {:.0} AU ({:.2} 光年)", r_tidal, r_tidal/63241.1);
println!("\n【Zone-07】日球层");
let P_ism = Zone07::ism_pressure();
let r_ts = Zone07::termination_shock_distance(7.0, 400.0);
let B_sheath = Zone07::heliosheath_magnetic_field();
let r_hp = Zone07::heliopause_distance(7.0, 400.0, B_sheath);
println!(" LISM总压力 = {:.6e} Pa", P_ism);
println!(" 终止激波(n=7,v=400) = {:.2} AU", r_ts);
println!(" 日球层顶(n=7,v=400) = {:.2} AU", r_hp);
let (n_ion, n_H, B_uG, v_ism, T_ism) = Zone07::lism_parameters();
println!(" LISM: n_ion={:.2} cm⁻³, n_H={:.2} cm⁻³, B={:.1} μG, v={:.1} km/s, T={:.0} K", n_ion, n_H, B_uG, v_ism, T_ism);
println!("\n【冰线位置】");
let d_water = IceLine::current_water_ice_line();
let d_co2 = IceLine::co2_ice_line();
let d_co = IceLine::co_ice_line();
println!(" 水冰线(170K) = {:.4} AU", d_water);
println!(" CO₂冰线(80K) = {:.4} AU", d_co2);
println!(" CO冰线(22K) = {:.4} AU", d_co);
println!("\n【通信导航约束】");
let delay_mars = Navigation::light_time_delay(1.5 * AU);
let delay_neptune = Navigation::light_time_delay(30.0 * AU);
let fspl_1au = Navigation::fspl_db(AU, 8.4e9);
let fspl_30au = Navigation::fspl_db(30.0 * AU, 8.4e9);
let doppler = Navigation::relativistic_doppler_shift(10000.0, 8.4e9);
let doppler_base = Navigation::relativistic_doppler_shift(-10000.0, 8.4e9);
println!(" 光时延迟@火星 = {:.4} s ({:.2} min)", delay_mars, delay_mars/60.0);
println!(" 光时延迟@海王星 = {:.4} s ({:.2} h)", delay_neptune, delay_neptune/3600.0);
println!(" FSPL@1AU, X-band = {:.2} dB", fspl_1au);
println!(" FSPL@30AU, X-band = {:.2} dB", fspl_30au);
println!(" Doppler(10km/s接近, 8.4GHz) = {:.6e} Hz", doppler - 8.4e9);
println!(" Doppler(10km/s远离, 8.4GHz) = {:.6e} Hz", doppler_base - 8.4e9);
println!(" 太阳常数@1AU = {:.2} W/m²", Zone02::solar_constant_at_distance(1.0, 1361.0));
println!(" 太阳常数@5AU = {:.4} W/m²", Zone02::solar_constant_at_distance(5.0, 1361.0));
println!(" 太阳常数@30AU = {:.6} W/m²", Zone02::solar_constant_at_distance(30.0, 1361.0));
println!("");
println!("════════════════════════════════════════════════════════════════════════════════");
}
}
fn main() {
SolarSystemBenchmark::print_full_report();
println!("");
println!("================================================================================");
println!("运行测试: cargo test");
println!("================================================================================");
}