pub struct OceanEndpoint {
pub wind_speed_m_s: f64,
pub wind_direction: [f64; 2],
pub fetch_km: f64,
pub mean_depth_m: f64,
pub salinity_psu: f64,
pub surface_temperature_k: f64,
pub surface_gravity_m_s2: f64,
pub ior: f64,
pub absorption_coefficients_rgb_m: [f64; 3],
pub foam_threshold_wind_m_s: f64,
pub grid_size: u32,
pub patch_size_m: f64,
}
impl OceanEndpoint {
pub fn earth_atlantic() -> Self {
Self {
wind_speed_m_s: 10.0,
wind_direction: [1.0, 0.0],
fetch_km: 500.0,
mean_depth_m: 3_646.0,
salinity_psu: 35.0,
surface_temperature_k: 290.0,
surface_gravity_m_s2: 9.806_65,
ior: 1.333,
absorption_coefficients_rgb_m: [0.45, 0.063, 0.019],
foam_threshold_wind_m_s: 7.0,
grid_size: 512,
patch_size_m: 1_000.0,
}
}
pub fn earth_pacific() -> Self {
Self {
wind_speed_m_s: 8.0,
wind_direction: [0.7, 0.7],
fetch_km: 800.0,
mean_depth_m: 4_280.0,
salinity_psu: 34.5,
surface_temperature_k: 293.0,
surface_gravity_m_s2: 9.806_65,
ior: 1.333,
absorption_coefficients_rgb_m: [0.45, 0.063, 0.019],
foam_threshold_wind_m_s: 7.0,
grid_size: 512,
patch_size_m: 1_000.0,
}
}
pub fn earth_arctic() -> Self {
Self {
wind_speed_m_s: 12.0,
wind_direction: [0.5, -0.5],
fetch_km: 200.0,
mean_depth_m: 1_205.0,
salinity_psu: 30.0,
surface_temperature_k: 271.5,
surface_gravity_m_s2: 9.806_65,
ior: 1.309,
absorption_coefficients_rgb_m: [0.42, 0.058, 0.017],
foam_threshold_wind_m_s: 6.0,
grid_size: 512,
patch_size_m: 1_000.0,
}
}
pub fn fresnel_r0(&self) -> f64 {
((self.ior - 1.0) / (self.ior + 1.0)).powi(2)
}
pub fn wave_amplitude(&self) -> f64 {
let w = self.wind_speed_m_s.max(0.1);
let grav = self.surface_gravity_m_s2;
let fetch_m = self.fetch_km * 1000.0;
let alpha_pm = 8.1e-3;
let beta_pm = 0.74;
let omega_p = grav / w * (beta_pm * (grav * fetch_m / (w * w)).powf(-0.33));
let k_peak = omega_p * omega_p / grav;
let pm_peak = alpha_pm * grav * grav / omega_p.powi(5)
* (-beta_pm * (grav / (omega_p * w)).powi(4)).exp();
let ocean_dx = self.patch_size_m / self.grid_size as f64;
let nyquist_k = std::f64::consts::PI / ocean_dx;
(2.0 * pm_peak / k_peak.min(nyquist_k))
.sqrt()
.clamp(0.01, 20.0)
}
pub fn depth_color(&self, depth: f64) -> [f64; 3] {
let d = depth.min(200.0);
[
(-self.absorption_coefficients_rgb_m[0] * d).exp(),
(-self.absorption_coefficients_rgb_m[1] * d).exp(),
(-self.absorption_coefficients_rgb_m[2] * d).exp(),
]
}
}