earths 0.0.3

High-fidelity Earth simulation engine — orbit, atmosphere, geology, hydrology, biosphere, terrain, lighting, rendering, satellites, and temporal systems with full scientific coupling
Documentation
use earths::physics::collisions::{Impactor, chicxulubequivalent, tunguskaequivalent};
use earths::physics::orbit::{
    ARGUMENTPERIHELIONDEG, ECCENTRICITY, EarthOrbit, INCLINATIONDEG, LONGITUDEASCENDINGNODEDEG,
    SEMIMAJORAXIS,
};
use earths::physics::rotation::{
    AXIALTILTDEG, AXIALTILTRAD, EarthRotation, PRECESSIONPERIODYEARS, SIDEREALDAYS, SOLARDAYS,
};
use earths::physics::tides::{
    TidalForce, lunartosolartideratio, neaptideamplitude, springtideamplitude,
};

#[test]
fn orbitalperiodabout365days() {
    let orbit = EarthOrbit::new();
    let days = orbit.orbitalperioddays();
    assert!((days - 365.25).abs() < 1.0);
}

#[test]
fn perihelioncloserthanaphelion() {
    let orbit = EarthOrbit::new();
    assert!(orbit.perihelionm() < orbit.aphelionm());
}

#[test]
fn velocityhigheratperihelion() {
    let orbit = EarthOrbit::new();
    let vperi = orbit.velocityatdistance(orbit.perihelionm());
    let vaph = orbit.velocityatdistance(orbit.aphelionm());
    assert!(vperi > vaph);
}

#[test]
fn orbital_energy_negative_bound() {
    let orbit = EarthOrbit::new();
    let e = orbit.specific_orbital_energy();
    assert!(e < 0.0);
}

#[test]
fn angular_momentum_positive() {
    let orbit = EarthOrbit::new();
    let l = orbit.specific_angular_momentum();
    assert!(l > 0.0);
}

#[test]
fn escape_velocity_about_11kms() {
    let vesc = EarthOrbit::escape_velocity_at_surface();
    let vkms = vesc / 1000.0;
    assert!((vkms - 11.2).abs() < 0.5);
}

#[test]
fn gravitational_force_sun_positive() {
    let orbit = EarthOrbit::new();
    let f = orbit.gravitational_force_sun();
    assert!(f > 3e22);
}

#[test]
fn current_radius_at_zero_anomaly() {
    let orbit = EarthOrbit::new();
    let r = orbit.current_radius();
    let expected = orbit.perihelionm();
    assert!((r - expected).abs() / expected < 1e-10);
}

#[test]
fn mean_orbital_velocity_about_30kms() {
    let orbit = EarthOrbit::new();
    let v = orbit.mean_orbital_velocity() / 1000.0;
    assert!((v - 29.8).abs() < 1.0);
}

#[test]
fn orbitalconstantsvalid() {
    const { assert!(SEMIMAJORAXIS > 1.49e11 && SEMIMAJORAXIS < 1.50e11) };
    const { assert!(ECCENTRICITY > 0.0 && ECCENTRICITY < 0.1) };
    const { assert!(INCLINATIONDEG < 1.0) };
    const { assert!(LONGITUDEASCENDINGNODEDEG < 360.0) };
    const { assert!(ARGUMENTPERIHELIONDEG > 0.0 && ARGUMENTPERIHELIONDEG < 360.0) };
}

#[test]
fn surfacevelocitymaxatequator() {
    let rot = EarthRotation::new();
    let veq = rot.surfacevelocityatlatitude(0.0);
    let v45 = rot.surfacevelocityatlatitude(45.0);
    let v90 = rot.surfacevelocityatlatitude(90.0);
    assert!(veq > v45);
    assert!(v45 > v90);
    assert!((veq - 465.0).abs() < 5.0);
}

#[test]
fn centripetalaccelerationmaxatequator() {
    let rot = EarthRotation::new();
    let aeq = rot.centripetalaccelerationatlatitude(0.0);
    let a45 = rot.centripetalaccelerationatlatitude(45.0);
    assert!(aeq > a45);
    assert!(aeq > 0.03);
}

#[test]
fn coriolisparameterzeroatequator() {
    let rot = EarthRotation::new();
    let f = rot.coriolisparameter(0.0);
    assert!(f.abs() < 1e-10);
}

#[test]
fn momentofinertiacorrectorder() {
    let rot = EarthRotation::new();
    let i = rot.momentofinertia();
    assert!(i > 8e37 && i < 9e37);
}

#[test]
fn rotationalkineticenergyhuge() {
    let rot = EarthRotation::new();
    let ke = rot.rotationalkineticenergy();
    assert!(ke > 2e29);
}

#[test]
fn angular_momentum_conserved_sign() {
    let rot = EarthRotation::new();
    let l = rot.angular_momentum();
    assert!(l > 0.0);
}

#[test]
fn precessionratesmall() {
    let rot = EarthRotation::new();
    let rate = rot.precession_rate_rad_per_year();
    assert!(rate > 0.0);
    assert!(rate < 0.001);
}

#[test]
fn daylengthsummerlongerthanwinter() {
    let rot = EarthRotation::new();
    let summer = rot.day_length_variation_due_to_tilt(172, 50.0);
    let winter = rot.day_length_variation_due_to_tilt(355, 50.0);
    assert!(summer > winter);
    assert!(summer > 12.0);
    assert!(winter < 12.0);
}

#[test]
fn polarday24hours() {
    let rot = EarthRotation::new();
    let arcticsummer = rot.day_length_variation_due_to_tilt(172, 80.0);
    assert!((arcticsummer - 24.0).abs() < 0.1);
}

#[test]
fn rotationconstantsvalid() {
    const { assert!(SIDEREALDAYS < SOLARDAYS) };
    assert!((AXIALTILTDEG - 23.44).abs() < 0.1);
    assert!((AXIALTILTRAD - AXIALTILTDEG.to_radians()).abs() < 0.01);
    const { assert!(PRECESSIONPERIODYEARS > 25000.0) };
}

#[test]
fn lunartidelargerthansolar() {
    let moon = TidalForce::frommoon();
    let sun = TidalForce::fromsun();
    assert!(moon.tidalacceleration() > sun.tidalacceleration());
}

#[test]
fn tidalratioabout22() {
    let ratio = lunartosolartideratio();
    assert!((ratio - 2.2).abs() < 0.5);
}

#[test]
fn springtidelargerthanneap() {
    let spring = springtideamplitude();
    let neap = neaptideamplitude();
    assert!(spring > neap);
    assert!(spring > 0.0);
    assert!(neap > 0.0);
}

#[test]
fn tidalpotentialvarieswithangle() {
    let moon = TidalForce::frommoon();
    let pot0 = moon.tidalpotential(0.0);
    let pot90 = moon.tidalpotential(std::f64::consts::FRAC_PI_2);
    assert!(pot0 != pot90);
}

#[test]
fn tidalbulgeheightpositive() {
    let moon = TidalForce::frommoon();
    let h = moon.tidalbulgeheight();
    assert!(h > 0.0);
    assert!(h < 1.0);
}

#[test]
fn gravitationalattractionmoonpositive() {
    let moon = TidalForce::frommoon();
    let f = moon.gravitationalattraction();
    assert!(f > 1e20);
}

#[test]
fn gravitationalattractionsunmuchlarger() {
    let moon = TidalForce::frommoon();
    let sun = TidalForce::fromsun();
    assert!(sun.gravitationalattraction() > moon.gravitationalattraction());
}

#[test]
fn chicxulubenormousenergy() {
    let chix = chicxulubequivalent();
    let energymt = chix.kineticenergymt();
    assert!(energymt > 1e6);
}

#[test]
fn tunguskasmallerthanchicxulub() {
    let tung = tunguskaequivalent();
    let chix = chicxulubequivalent();
    assert!(tung.kineticenergyj() < chix.kineticenergyj());
}

#[test]
fn impactvelocityhigherthanapproach() {
    let imp = Impactor::asteroid(1000.0, 15.0);
    let vimpact = imp.impactvelocity();
    assert!(vimpact > imp.velocityms);
}

#[test]
fn craterdiameterincreaseswithimpactorsize() {
    let small = Impactor::asteroid(100.0, 20.0);
    let large = Impactor::asteroid(10000.0, 20.0);
    let csmall = small.craterdiameterm(2700.0);
    let clarge = large.craterdiameterm(2700.0);
    assert!(clarge > csmall);
}

#[test]
fn fireballradiuspositive() {
    let imp = Impactor::asteroid(500.0, 18.0);
    let r = imp.fireballradiusm();
    assert!(r > 0.0);
}

#[test]
fn ejectavolumepositive() {
    let imp = Impactor::asteroid(1000.0, 20.0);
    let vol = imp.ejectavolumem3(2700.0);
    assert!(vol > 0.0);
}

#[test]
fn kineticenergymegatonsconsistent() {
    let imp = Impactor::asteroid(500.0, 15.0);
    let j = imp.kineticenergyj();
    let mt = imp.kineticenergymt();
    assert!((mt - j / 4.184e15).abs() < 1.0);
}