use serde::{Deserialize, Serialize};
use crate::error::{MimamsaError, ensure_finite, require_all_finite};
use tracing::instrument;
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct GeodesicPoint {
pub t: f64,
pub r: f64,
pub theta: f64,
pub phi: f64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub enum GeodesicType {
Timelike,
Null,
Spacelike,
}
#[instrument(level = "trace")]
#[inline]
pub fn schwarzschild_effective_potential(
rs: f64,
r: f64,
angular_momentum: f64,
geodesic_type: GeodesicType,
) -> Result<f64, MimamsaError> {
require_all_finite(
&[rs, r, angular_momentum],
"schwarzschild_effective_potential",
)?;
let factor = 1.0 - rs / r;
ensure_finite(
match geodesic_type {
GeodesicType::Timelike => {
let l2 = angular_momentum * angular_momentum;
factor * (1.0 + l2 / (r * r))
}
GeodesicType::Null => {
let l2 = angular_momentum * angular_momentum;
factor * l2 / (r * r)
}
GeodesicType::Spacelike => {
let l2 = angular_momentum * angular_momentum;
factor * (-1.0 + l2 / (r * r))
}
},
"schwarzschild_effective_potential",
)
}
#[instrument(level = "trace")]
#[inline]
pub fn light_deflection_weak_field(
mass_kg: f64,
impact_parameter: f64,
) -> Result<f64, MimamsaError> {
use crate::constants::{C, G};
require_all_finite(&[mass_kg, impact_parameter], "light_deflection_weak_field")?;
ensure_finite(
4.0 * G * mass_kg / (impact_parameter * C * C),
"light_deflection_weak_field",
)
}
#[instrument(level = "trace")]
pub fn shapiro_delay(
mass_kg: f64,
r1: f64,
r2: f64,
impact_parameter: f64,
) -> Result<f64, MimamsaError> {
use crate::constants::{C, G};
require_all_finite(&[mass_kg, r1, r2, impact_parameter], "shapiro_delay")?;
let c3 = C.powi(3);
let prefactor = 4.0 * G * mass_kg / c3;
ensure_finite(
prefactor * (4.0 * r1 * r2 / (impact_parameter * impact_parameter)).ln(),
"shapiro_delay",
)
}
#[cfg(test)]
mod tests {
use super::*;
use std::f64::consts::PI;
const M_SUN: f64 = 1.989e30;
const AU: f64 = 1.496e11;
#[test]
fn test_light_deflection_sun() {
let r_sun = 6.957e8; let deflection_rad = light_deflection_weak_field(M_SUN, r_sun).unwrap();
let deflection_arcsec = deflection_rad * 180.0 / PI * 3600.0;
assert!((deflection_arcsec - 1.75).abs() < 0.02);
}
#[test]
fn test_effective_potential_at_infinity() {
let rs = 2953.0; let v = schwarzschild_effective_potential(rs, 1e15, 1.0, GeodesicType::Timelike).unwrap();
assert!((v - 1.0).abs() < 1e-6);
}
#[test]
fn test_shapiro_delay_positive() {
let delay = shapiro_delay(M_SUN, AU, AU, 6.957e8).unwrap();
assert!(delay > 0.0);
assert!(delay > 1e-5 && delay < 1e-3);
}
#[test]
fn test_effective_potential_null_geodesic() {
let rs = 2953.0;
let v = schwarzschild_effective_potential(rs, 1e10, 1e5, GeodesicType::Null).unwrap();
assert!(v > 0.0);
}
#[test]
fn test_effective_potential_spacelike_geodesic() {
let rs = 2953.0;
let v = schwarzschild_effective_potential(rs, 1e10, 1e8, GeodesicType::Spacelike).unwrap();
assert!(v.is_finite());
}
}