use std::f64::consts::PI;
use crate::kepler::{principal_angle, UniversalKeplerParams};
fn initial_eccentric_anomaly_from_geometry(
radial_distance: f64,
semi_major_axis: f64,
eccentricity: f64,
radial_velocity_proxy: f64,
) -> f64 {
let cosine_of_eccentric_anomaly = (1.0 - radial_distance / semi_major_axis) / eccentricity;
let mut eccentric_anomaly = if cosine_of_eccentric_anomaly.abs() <= 1.0 {
cosine_of_eccentric_anomaly.acos()
} else if cosine_of_eccentric_anomaly >= 1.0 {
0.0 } else {
PI };
if radial_velocity_proxy < 0.0 {
eccentric_anomaly = -eccentric_anomaly;
}
principal_angle(eccentric_anomaly)
}
pub fn prelim_elliptic(params: &UniversalKeplerParams) -> f64 {
let contr = params.solver_type.params.convergency;
let max_iter = params.solver_type.params.max_iter_prelim_kepuni;
let semi_major_axis = -1.0 / params.alpha;
let mean_motion = params.mu.sqrt() * (-params.alpha.powi(3)).sqrt();
if params.e0 < contr {
return mean_motion * params.dt / (-params.alpha).sqrt();
}
let initial_eccentric_anomaly =
initial_eccentric_anomaly_from_geometry(params.r0, semi_major_axis, params.e0, params.sig0);
let mean_anomaly_at_epoch =
principal_angle(initial_eccentric_anomaly - params.e0 * initial_eccentric_anomaly.sin());
let target_mean_anomaly = mean_anomaly_at_epoch + mean_motion * params.dt;
let updated_eccentric_anomaly =
solve_elliptic_kepler_equation(target_mean_anomaly, params.e0, contr, max_iter);
(updated_eccentric_anomaly - initial_eccentric_anomaly) / (-params.alpha).sqrt()
}
fn solve_elliptic_kepler_equation(
target_mean_anomaly: f64,
eccentricity: f64,
convergence_threshold: f64,
max_iter: usize,
) -> f64 {
let mut eccentric_anomaly = target_mean_anomaly;
for _ in 0..max_iter {
let residual =
eccentric_anomaly - eccentricity * eccentric_anomaly.sin() - target_mean_anomaly;
let residual_derivative = 1.0 - eccentricity * eccentric_anomaly.cos();
let newton_step = -residual / residual_derivative;
eccentric_anomaly += newton_step;
if newton_step.abs() < convergence_threshold * 1e3 {
break;
}
}
eccentric_anomaly
}