import unittest
import numpy as np
from mapgen import climate as CL
from tests.helpers import small_grid
class InsolationTest(unittest.TestCase):
def test_insolation_finite_at_poles(self):
q = CL.insolation(np.array([90.0, -90.0, 89.999]), 20.0)
self.assertTrue(np.all(np.isfinite(q)))
self.assertAlmostEqual(q[1], 0.0, places=6) # polar night
self.assertGreater(q[0], 400) # polar day
def test_symmetry(self):
lat = np.linspace(-80, 80, 17)
np.testing.assert_allclose(CL.insolation(lat, 20.0), CL.insolation(-lat, -20.0), rtol=1e-12)
class TemperatureTest(unittest.TestCase):
def setUp(self):
self.g = small_grid(3)
self.P = dict(CL.DEFAULTS)
def test_aquaplanet_zonal_means_fall_poleward(self):
g = self.g
z = np.full(g.n, -4000.0)
T, _ = CL.temperatures(g, z, z > 0, self.P, 20.0)
tm = (T["jun"] + T["dec"] + 2 * T["eq"]) / 4
bands = [tm[(np.abs(g.lat) >= a) & (np.abs(g.lat) < a + 10)].mean() for a in range(0, 90, 10)]
self.assertTrue(all(b1 > b2 for b1, b2 in zip(bands, bands[1:])), bands)
self.assertTrue(20 < bands[0] < 32 and bands[-1] < -5, bands)
def test_lapse_rate(self):
g = self.g
land = (np.abs(g.lat) < 30) & (np.abs(g.lon) < 60)
flat = np.where(land, 10.0, -4000.0)
high = np.where(land & (np.abs(g.lon) < 20), 3000.0, flat)
T0, _ = CL.temperatures(g, flat, land, self.P, 20.0)
T1, _ = CL.temperatures(g, high, land, self.P, 20.0)
i = g.cell_index(0.0, 0.0)
self.assertAlmostEqual(T0["eq"][i] - T1["eq"][i], 6.5 * 2.99, delta=0.5)
def test_cold_west_coast_warm_east_coast(self):
g = self.g
land = (g.lat > 15) & (g.lat < 45) & (np.abs(g.lon) < 30)
a = CL.current_anomaly(g, land, self.P)
self.assertLess(a[g.cell_index(30.0, -33.0)], -0.5)
self.assertGreater(a[g.cell_index(30.0, 33.0)], 0.5)
def test_continental_interior_has_bigger_seasons(self):
g = self.g
land = (g.lat > 20) & (g.lat < 70) & (np.abs(g.lon) < 90)
z = np.where(land, 200.0, -4000.0)
T, _ = CL.temperatures(g, z, land, self.P, 20.0)
rng = np.abs(T["jun"] - T["dec"])
self.assertGreater(rng[g.cell_index(50.0, 0.0)], rng[g.cell_index(50.0, 150.0)] + 10)
def test_biotemperature(self):
bio = CL.biotemperature(np.array([10.0, -5.0, 35.0, 0.0]), np.array([0.0, 0.0, 0.0, 20.0]))
np.testing.assert_allclose(bio[:3], [10.0, 0.0, 30.0])
self.assertTrue(2.0 < bio[3] < 4.0)
class CalibrationTest(unittest.TestCase):
def test_earthlike_midlatitudes_and_sea_ice_edge(self):
g = small_grid(3)
z = np.full(g.n, -4000.0)
T, _ = CL.temperatures(g, z, z > 0, CL.DEFAULTS, 20.0)
tm = (T["jun"] + T["dec"] + 2 * T["eq"]) / 4
band = lambda a: np.abs(np.abs(g.lat) - a) < 2
self.assertTrue(10 < tm[band(45)].mean() < 18, tm[band(45)].mean())
self.assertTrue(-1 < tm[band(60)].mean() < 8, tm[band(60)].mean())
winter = np.where(g.lat >= 0, T["dec"], T["jun"])
self.assertGreater(winter[band(48)].mean(), -1.8) # no sea ice at 48°
self.assertLess(winter[band(66)].mean(), -1.8) # seasonal sea ice by 66°
def test_subtropical_land_heats_in_summer(self):
g = small_grid(3)
land = (g.lat > 10) & (g.lat < 40) & (np.abs(g.lon) < 50)
z = np.where(land, 200.0, -4000.0)
T, _ = CL.temperatures(g, z, land, CL.DEFAULTS, 20.0)
anom = T["jun"] - CL.zonal_mean(g, T["jun"])
self.assertGreater(anom[land].mean(), 2.5)
self.assertLess(T["jun"][land].max(), 42.0)
def test_ocean_seasonal_range_earthlike(self):
g = small_grid(3)
z = np.full(g.n, -4000.0)
T, _ = CL.temperatures(g, z, z > 0, CL.DEFAULTS, 20.0)
rng = np.abs(T["jun"] - T["dec"])[np.abs(np.abs(g.lat) - 50) < 2].mean()
self.assertTrue(4 < rng < 10, rng)