use sciforge::hub::domain::common::constants::{EARTH_MASS, EARTH_RADIUS, G, R_GAS};
use sciforge::hub::prelude::constants::elements::atomic_mass;
pub fn ice_density() -> f64 {
*crate::ICE_DENSITY
}
pub const ICE_CREEP_EXPONENT: f64 = 3.0;
pub const GLEN_FLOW_LAW_A: f64 = 2.4e-24;
pub fn water_molar_mass_from_elements() -> f64 {
2.0 * atomic_mass(1) + atomic_mass(8)
}
pub struct Glacier {
pub name: &'static str,
pub length_km: f64,
pub thickness_m: f64,
pub surface_slope_deg: f64,
pub accumulation_m_yr: f64,
pub ablation_m_yr: f64,
}
impl Glacier {
pub fn mass_balance_m_yr(&self) -> f64 {
self.accumulation_m_yr - self.ablation_m_yr
}
pub fn basal_shear_stress_pa(&self) -> f64 {
let g = G * EARTH_MASS / (EARTH_RADIUS * EARTH_RADIUS);
let slope_rad = self.surface_slope_deg.to_radians();
ice_density() * g * self.thickness_m * slope_rad.sin()
}
pub fn deformation_velocity_m_yr(&self) -> f64 {
let tau = self.basal_shear_stress_pa();
let n = ICE_CREEP_EXPONENT;
let velocity_m_s = 2.0 * GLEN_FLOW_LAW_A * tau.powf(n) * self.thickness_m / (n + 1.0);
velocity_m_s * crate::SECONDS_PER_YEAR
}
pub fn equilibrium_line_altitude(&self, base_elevation_m: f64) -> f64 {
base_elevation_m
+ self.length_km * 1000.0 * 0.5 * (self.surface_slope_deg.to_radians()).tan()
}
pub fn volume_m3(&self, width_m: f64) -> f64 {
self.length_km * 1000.0 * width_m * self.thickness_m * 0.7
}
pub fn sea_level_equivalent_mm(&self, width_m: f64) -> f64 {
let vol = self.volume_m3(width_m);
let ocean_area = crate::OCEAN_SURFACE_AREA;
vol * ice_density() / 1000.0 / ocean_area * 1000.0
}
}
pub fn antarctic_ice_sheet() -> Glacier {
Glacier {
name: "Antarctic Ice Sheet",
length_km: 4500.0,
thickness_m: 2160.0,
surface_slope_deg: 0.1,
accumulation_m_yr: 0.166,
ablation_m_yr: 0.150,
}
}
pub fn greenland_ice_sheet() -> Glacier {
Glacier {
name: "Greenland Ice Sheet",
length_km: 2400.0,
thickness_m: 1500.0,
surface_slope_deg: 0.3,
accumulation_m_yr: 0.34,
ablation_m_yr: 0.32,
}
}
pub fn ice_rheology_viscosity(temperature_c: f64, stress_pa: f64) -> f64 {
let temp_k = temperature_c + crate::CELSIUS_TO_KELVIN;
let q = crate::Q_ICE_CREEP;
let a = GLEN_FLOW_LAW_A * (-q / (R_GAS * temp_k)).exp();
1.0 / (2.0 * a * stress_pa.powf(ICE_CREEP_EXPONENT - 1.0))
}
pub fn glen_strain_rate(temperature_c: f64, stress_pa: f64) -> f64 {
let temp_k = temperature_c + crate::CELSIUS_TO_KELVIN;
let q = crate::Q_ICE_CREEP;
let a_temp = GLEN_FLOW_LAW_A * (-q / (R_GAS * temp_k)).exp();
a_temp * stress_pa.powf(ICE_CREEP_EXPONENT)
}
pub fn shallow_ice_velocity(thickness_m: f64, slope_rad: f64, temperature_c: f64) -> f64 {
let temp_k = temperature_c + crate::CELSIUS_TO_KELVIN;
let q = crate::Q_ICE_CREEP;
let a_temp = GLEN_FLOW_LAW_A * (-q / (R_GAS * temp_k)).exp();
let g = G * EARTH_MASS / (EARTH_RADIUS * EARTH_RADIUS);
let n = ICE_CREEP_EXPONENT;
let driving_stress = ice_density() * g * slope_rad.sin().abs();
2.0 * a_temp / (n + 1.0) * driving_stress.powf(n) * thickness_m.powf(n + 1.0)
}
pub fn glacial_bed_erosion_rate(
basal_velocity_m_s: f64,
ice_thickness_m: f64,
water_pressure_pa: f64,
) -> f64 {
const K_G: f64 = 1e-4;
const L_HALLET: f64 = 2.0;
const P_STRESS_EXP: f64 = 1.0;
const N_REF_PA: f64 = 1.0e6;
let g = G * EARTH_MASS / (EARTH_RADIUS * EARTH_RADIUS);
let overburden = ice_density() * g * ice_thickness_m;
let n_eff = (overburden - water_pressure_pa).max(0.0);
let stress_ratio = (n_eff / N_REF_PA).powf(P_STRESS_EXP);
K_G * basal_velocity_m_s.abs().powf(L_HALLET) * stress_ratio
}