use super::hyperdual::{hyperspace_from_vector, linalg::norm, Hyperdual};
use super::ForceModel;
use crate::celestia::eclipse::EclipseLocator;
use crate::celestia::{Cosm, Frame, Spacecraft, AU, SPEED_OF_LIGHT};
use crate::dimensions::{DimName, Matrix3, Vector3, U3, U7};
use crate::errors::NyxError;
use std::sync::Arc;
#[derive(Clone)]
pub struct SolarPressure {
pub phi: f64,
pub e_loc: EclipseLocator,
}
impl<'a> SolarPressure {
pub fn default_raw(shadow_bodies: Vec<Frame>, cosm: Arc<Cosm>) -> Self {
let e_loc = EclipseLocator {
light_source: cosm.frame("Sun J2000"),
shadow_bodies,
cosm,
};
Self { phi: 1367.0, e_loc }
}
pub fn default(shadow_body: Frame, cosm: Arc<Cosm>) -> Arc<Self> {
Arc::new(Self::default_raw(vec![shadow_body], cosm))
}
pub fn with_flux(flux_w_m2: f64, shadow_bodies: Vec<Frame>, cosm: Arc<Cosm>) -> Arc<Self> {
let mut me = Self::default_raw(shadow_bodies, cosm);
me.phi = flux_w_m2;
Arc::new(me)
}
}
impl ForceModel for SolarPressure {
fn eom(&self, ctx: &Spacecraft) -> Result<Vector3<f64>, NyxError> {
let osc = &ctx.orbit;
let r_sun = self
.e_loc
.cosm
.frame_chg(osc, self.e_loc.light_source)
.radius();
let r_sun_unit = r_sun / r_sun.norm();
let k = self.e_loc.compute(osc).as_f64();
let r_sun_au = r_sun.norm() / AU;
let flux_pressure = (k * self.phi / SPEED_OF_LIGHT) * (1.0 / r_sun_au).powi(2);
Ok(1e-3 * ctx.cr * ctx.srp_area_m2 * flux_pressure * r_sun_unit)
}
fn dual_eom(
&self,
_radius: &Vector3<Hyperdual<f64, U7>>,
ctx: &Spacecraft,
) -> Result<(Vector3<f64>, Matrix3<f64>), NyxError> {
let osc = &ctx.orbit;
let r_sun = self
.e_loc
.cosm
.frame_chg(osc, self.e_loc.light_source)
.radius();
let r_sun_d: Vector3<Hyperdual<f64, U7>> = hyperspace_from_vector(&r_sun);
let r_sun_unit = r_sun_d / norm(&r_sun_d);
let k = self.e_loc.compute(osc).as_f64();
let inv_r_sun_au = Hyperdual::<f64, U7>::from_real(1.0) / (norm(&r_sun_d) / AU);
let inv_r_sun_au_p2 = inv_r_sun_au * inv_r_sun_au;
let flux_pressure =
Hyperdual::<f64, U7>::from_real(k * self.phi / SPEED_OF_LIGHT) * inv_r_sun_au_p2;
let dual_force_scalar =
Hyperdual::<f64, U7>::from_real(1e-3 * ctx.cr * ctx.srp_area_m2) * flux_pressure;
let mut dual_force: Vector3<Hyperdual<f64, U7>> = Vector3::zeros();
dual_force[0] = dual_force_scalar * r_sun_unit[0];
dual_force[1] = dual_force_scalar * r_sun_unit[1];
dual_force[2] = dual_force_scalar * r_sun_unit[2];
let mut fx = Vector3::zeros();
let mut grad = Matrix3::zeros();
for i in 0..U3::dim() {
fx[i] += dual_force[i][0];
for j in 0..U3::dim() {
grad[(i, j)] += dual_force[i][j + 1];
}
}
Ok((fx, grad))
}
}