use crate::{C_SQUARED, Drift, Position, Real, Velocity, sqrt};
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "tsify", derive(tsify::Tsify))]
pub struct Spacetime {
pub alpha: Real,
pub beta: Real,
pub kretschmann: Real,
}
impl Spacetime {
#[inline]
pub const fn new(alpha: Real, beta: Real, kretschmann: Real) -> Spacetime {
Self {
alpha,
beta,
kretschmann,
}
}
#[inline]
pub const fn proper_time_rate(&self) -> Real {
Drift::from_spacetime(self).proper_time_rate()
}
#[inline]
pub const fn from_gravitic_and_velocity(
alpha: Real,
velocity: Velocity,
kretschmann: Real,
) -> Spacetime {
Self::new(alpha, velocity.beta(), kretschmann)
}
#[inline]
pub const fn alpha_from_weak_field_potential(grav_potential_over_c2: Real) -> Real {
sqrt((f!(1.0) + f!(2.0) * grav_potential_over_c2).max(f!(0.0)))
}
pub const fn kretschmann_from_potential_and_scale(
grav_potential_over_c2: Real,
characteristic_length_scale: Real,
) -> Real {
if characteristic_length_scale <= f!(0.0) {
return f!(0.0);
}
let curvature_scale = f!(2.0) * grav_potential_over_c2
/ (characteristic_length_scale * characteristic_length_scale);
f!(12.0) * (curvature_scale * curvature_scale)
}
pub const fn from_potential_velocity_and_scale(
grav_potential_over_c2: Real, velocity: Velocity,
characteristic_length_scale: Real,
) -> Spacetime {
let alpha: Real = Self::alpha_from_weak_field_potential(grav_potential_over_c2);
let kretschmann: Real = Self::kretschmann_from_potential_and_scale(
grav_potential_over_c2,
characteristic_length_scale,
);
Self::from_gravitic_and_velocity(alpha, velocity, kretschmann)
}
#[inline]
pub const fn grav_potential_from_alpha(alpha: Real) -> Real {
let alpha_sq = alpha * alpha;
(alpha_sq - f!(1.0)) / f!(2.0) * C_SQUARED
}
pub fn grav_potential_from_point_masses<I>(position: &Position, bodies: I) -> Real
where
I: IntoIterator<Item = (Position, Real)>, {
let mut phi = 0.0;
for (body_pos, gm) in bodies {
let r = position.distance_to(&body_pos);
if r > 0.0 {
phi -= gm / r;
}
}
phi
}
}
#[cfg(feature = "wire")]
impl Spacetime {
pub const WIRE_SIZE: usize = 24;
pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
let mut buf = [0u8; Self::WIRE_SIZE];
buf[0..8].copy_from_slice(&self.alpha.to_le_bytes());
buf[8..16].copy_from_slice(&self.beta.to_le_bytes());
buf[16..24].copy_from_slice(&self.kretschmann.to_le_bytes());
buf
}
pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
if bytes.len() != Self::WIRE_SIZE {
return None;
}
let alpha = Real::from_le_bytes([
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
]);
let beta = Real::from_le_bytes([
bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15],
]);
let kretschmann = Real::from_le_bytes([
bytes[16], bytes[17], bytes[18], bytes[19], bytes[20], bytes[21], bytes[22], bytes[23],
]);
Some(Self {
alpha,
beta,
kretschmann,
})
}
}