use nalgebra as na;
use crate::nrlmsise::nrlmsise;
use crate::AstroTime;
use crate::ITRFCoord;
const OMEGA_EARTH: na::Vector3<f64> = na::vector![0.0, 0.0, crate::consts::OMEGA_EARTH];
const OMEGA_EARTH_MATRIX: na::Matrix3<f64> = na::Matrix3::new(
0.0,
-crate::consts::OMEGA_EARTH,
0.0,
crate::consts::OMEGA_EARTH,
0.0,
0.0,
0.0,
0.0,
0.0,
);
pub fn drag_force(
pos_gcrf: &na::Vector3<f64>,
pos_itrf: &na::Vector3<f64>,
vel_gcrf: &na::Vector3<f64>,
time: &crate::AstroTime,
cd_a_over_m: f64,
use_spaceweather: bool,
) -> na::Vector3<f64> {
let itrf = ITRFCoord::from(pos_itrf.as_slice());
let (density, _temperature) = nrlmsise(
itrf.hae() / 1.0e3,
Some(itrf.latitude_rad()),
Some(itrf.longitude_rad()),
Some(*time),
use_spaceweather,
);
let vrel = vel_gcrf - OMEGA_EARTH.cross(&pos_gcrf);
let drag_accel_gcrf = -0.5 * cd_a_over_m * density * vrel * vrel.norm();
drag_accel_gcrf
}
fn compute_rho_drhodr(
pgcrf: &na::Vector3<f64>,
qgcrf2itrf: &crate::frametransform::Quat,
time: &AstroTime,
use_spaceweather: bool,
) -> (f64, na::Vector3<f64>) {
let dx = 100.0;
let pitrf = qgcrf2itrf * pgcrf;
let itrf = ITRFCoord::from(pitrf);
let qned2itrf = itrf.q_ned2itrf();
let offset_vecs = vec![
na::vector![dx, 0.0, 0.0],
na::vector![0.0, dx, 0.0],
na::vector![0.0, 0.0, dx],
];
let (density0, _temperature) = crate::nrlmsise::nrlmsise(
itrf.hae() / 1.0e3,
Some(itrf.latitude_rad()),
Some(itrf.longitude_rad()),
Some(*time),
use_spaceweather,
);
let drhodr_ned: Vec<f64> = offset_vecs
.iter()
.map(|v| {
let itrf_off = itrf + qned2itrf * v;
let (density, _temperature) = crate::nrlmsise::nrlmsise(
itrf_off.hae() / 1.0e3,
Some(itrf_off.latitude_rad()),
Some(itrf_off.longitude_rad()),
Some(*time),
use_spaceweather,
);
(density - density0) / dx
})
.collect();
let qned2gcrf = qgcrf2itrf.conjugate() * qned2itrf;
(
density0,
qned2gcrf * na::vector![drhodr_ned[0], drhodr_ned[1], drhodr_ned[2]],
)
}
pub fn drag_and_partials(
pos_gcrf: &na::Vector3<f64>,
qgcrf2itrf: &na::UnitQuaternion<f64>,
vel_gcrf: &na::Vector3<f64>,
time: &crate::AstroTime,
cd_a_over_m: f64,
use_spaceweather: bool,
) -> (na::Vector3<f64>, na::Matrix3<f64>, na::Matrix3<f64>) {
let (density, drhodr) = compute_rho_drhodr(&pos_gcrf, &qgcrf2itrf, &time, use_spaceweather);
let vrel = vel_gcrf - OMEGA_EARTH.cross(&pos_gcrf);
let drag_accel_gcrf = -0.5 * cd_a_over_m * density * vrel * vrel.norm();
let dacceldv = -0.5
* cd_a_over_m
* density
* (vrel * vrel.transpose() / vrel.norm() + vrel.norm() * na::Matrix3::<f64>::identity());
let dacceldr = -0.5 * cd_a_over_m * density * vrel * vrel.norm() * drhodr.transpose()
- dacceldv * OMEGA_EARTH_MATRIX;
(drag_accel_gcrf, dacceldr, dacceldv)
}