use sciforge::hub::domain::common::constants::{EARTH_MASS, EARTH_RADIUS, G, R_GAS};
use sciforge::hub::prelude::constants::elements::atomic_mass;
pub fn icedensity() -> f64 {
*crate::ICEDENSITY
}
pub const ICECREEPEXPONENT: f64 = 3.0;
pub const GLENFLOWLAWA: f64 = 2.4e-24;
pub fn watermolarmassfromelements() -> f64 {
2.0 * atomic_mass(1) + atomic_mass(8)
}
pub struct Glacier {
pub name: &'static str,
pub lengthkm: f64,
pub thicknessm: f64,
pub surfaceslopedeg: f64,
pub accumulationmyr: f64,
pub ablationmyr: f64,
}
impl Glacier {
pub fn massbalancemyr(&self) -> f64 {
self.accumulationmyr - self.ablationmyr
}
pub fn basalshearstresspa(&self) -> f64 {
let g = G * EARTH_MASS / (EARTH_RADIUS * EARTH_RADIUS);
let sloperad = self.surfaceslopedeg.to_radians();
icedensity() * g * self.thicknessm * sloperad.sin()
}
pub fn deformationvelocitymyr(&self) -> f64 {
let tau = self.basalshearstresspa();
let n = ICECREEPEXPONENT;
let velocityms = 2.0 * GLENFLOWLAWA * tau.powf(n) * self.thicknessm / (n + 1.0);
velocityms * crate::SECONDSPERYEAR
}
pub fn equilibriumlinealtitude(&self, baseelevationm: f64) -> f64 {
baseelevationm + self.lengthkm * 1000.0 * 0.5 * (self.surfaceslopedeg.to_radians()).tan()
}
pub fn volumem3(&self, widthm: f64) -> f64 {
self.lengthkm * 1000.0 * widthm * self.thicknessm * 0.7
}
pub fn sealevelequivalentmm(&self, widthm: f64) -> f64 {
let vol = self.volumem3(widthm);
let oceanarea = crate::OCEANSURFACEAREA;
vol * icedensity() / 1000.0 / oceanarea * 1000.0
}
}
pub fn antarcticicesheet() -> Glacier {
Glacier {
name: "Antarctic Ice Sheet",
lengthkm: 4500.0,
thicknessm: 2160.0,
surfaceslopedeg: 0.1,
accumulationmyr: 0.166,
ablationmyr: 0.150,
}
}
pub fn greenlandicesheet() -> Glacier {
Glacier {
name: "Greenland Ice Sheet",
lengthkm: 2400.0,
thicknessm: 1500.0,
surfaceslopedeg: 0.3,
accumulationmyr: 0.34,
ablationmyr: 0.32,
}
}
pub fn icerheologyviscosity(temperaturec: f64, stresspa: f64) -> f64 {
let tempk = temperaturec + crate::CELSIUSTOKELVIN;
let q = crate::QICECREEP;
let a = GLENFLOWLAWA * (-q / (R_GAS * tempk)).exp();
1.0 / (2.0 * a * stresspa.powf(ICECREEPEXPONENT - 1.0))
}
pub fn glenstrainrate(temperaturec: f64, stresspa: f64) -> f64 {
let tempk = temperaturec + crate::CELSIUSTOKELVIN;
let q = crate::QICECREEP;
let atemp = GLENFLOWLAWA * (-q / (R_GAS * tempk)).exp();
atemp * stresspa.powf(ICECREEPEXPONENT)
}
pub fn shallowicevelocity(thicknessm: f64, sloperad: f64, temperaturec: f64) -> f64 {
let tempk = temperaturec + crate::CELSIUSTOKELVIN;
let q = crate::QICECREEP;
let atemp = GLENFLOWLAWA * (-q / (R_GAS * tempk)).exp();
let g = G * EARTH_MASS / (EARTH_RADIUS * EARTH_RADIUS);
let n = ICECREEPEXPONENT;
let drivingstress = icedensity() * g * sloperad.sin().abs();
2.0 * atemp / (n + 1.0) * drivingstress.powf(n) * thicknessm.powf(n + 1.0)
}
pub fn glacialbederosionrate(
basalvelocityms: f64,
icethicknessm: f64,
waterpressurepa: f64,
) -> f64 {
const KG: f64 = 1e-4;
const LHALLET: f64 = 2.0;
const PSTRESSEXP: f64 = 1.0;
const NREFPA: f64 = 1.0e6;
let g = G * EARTH_MASS / (EARTH_RADIUS * EARTH_RADIUS);
let overburden = icedensity() * g * icethicknessm;
let neff = (overburden - waterpressurepa).max(0.0);
let stressratio = (neff / NREFPA).powf(PSTRESSEXP);
KG * basalvelocityms.abs().powf(LHALLET) * stressratio
}