Files
exoplasim/tests/test_web_planet.py

102 lines
5.2 KiB
Python

import json
from pathlib import Path
import tempfile
import unittest
import numpy as np
from scripts.web import terrain as planet
from scripts.web.config import load_config
from scripts.web.parameters import catalog, validate_spec
class PlanetTests(unittest.TestCase):
def setUp(self):
self.temp = tempfile.TemporaryDirectory()
self.root = Path(self.temp.name)
self.config = load_config()
self.config['storage']['root'] = str(self.root)
self.config['storage']['catalog'] = 'catalog.json'
path = self.root / 'catalog.json'
path.write_text(json.dumps(catalog(self.config)))
self.config['_paths']['catalog'] = str(path)
def tearDown(self):
self.temp.cleanup()
def recipe(self, seed=21, resolution='T21', land_fraction=.31):
return {'model': {'resolution': resolution, 'layers': 10, 'ncpus': 1}, 'parameters': {},
'run': self.config['run_defaults'],
'surface': {'seed': seed, 'land_fraction': land_fraction, 'relief': 5000, 'scale': 4}}
def test_deterministic_valid_spec_and_seed_changes(self):
first = planet.generate_planet(self.recipe(), self.config, self.root / 'a')
second = planet.generate_planet(self.recipe(), self.config, self.root / 'b')
self.assertEqual(first['spec'], second['spec'])
self.assertTrue(validate_spec(first['spec'], self.config)['ok'])
self.assertTrue(.5 <= first['spec']['parameters']['rotationperiod'] <= 2)
with np.load(first['dataset']['preview']) as a, np.load(second['dataset']['preview']) as b:
np.testing.assert_array_equal(a['elevation'], b['elevation'])
third = planet.generate_planet(self.recipe(seed=22), self.config, self.root / 'c')
self.assertNotEqual(first['dataset']['id'], third['dataset']['id'])
def test_terrain_seam_and_poles(self):
lat = np.array([90., 0., -90.])
lon = np.array([0., 90., 180., 270., 360.])
field = planet._terrain(self.recipe()['surface'], lat, lon, np.ones(len(lat)))
np.testing.assert_allclose(field[:, 0], field[:, -1], atol=1e-12)
np.testing.assert_allclose(field[0], field[0, 0], atol=1e-12)
np.testing.assert_allclose(field[-1], field[-1, 0], atol=1e-12)
def test_grid_sizes_and_finite_fields(self):
for resolution in self.config['limits']['resolutions']:
with self.subTest(resolution=resolution):
result = planet.generate_planet(self.recipe(resolution=resolution), self.config, self.root / resolution)
with np.load(result['dataset']['preview']) as data:
nlat = len(data['lat'])
self.assertEqual(data['elevation'].shape, (1, nlat, nlat * 2))
self.assertTrue(np.isfinite(data['elevation']).all())
self.assertTrue(np.isfinite(data['bathymetry']).all())
self.assertTrue(np.all(np.diff(data['lat']) < 0))
def test_weighted_land_fraction_and_extremes(self):
for fraction in (0, .4, 1):
config = dict(self.config, gravity=8.2)
ds = planet.prepare_surface(self.recipe(land_fraction=fraction)['surface'], self.recipe()['model'], config, self.root / str(fraction))
self.assertLess(abs(ds['land_fraction_actual'] - fraction), .001)
with np.load(ds['preview']) as archive:
self.assertEqual(float(archive['landmask'].min()), float(fraction == 1))
self.assertEqual(float(archive['landmask'].max()), float(fraction != 0))
np.testing.assert_array_equal(archive['bathymetry'], np.minimum(archive['elevation'], 0))
def test_sra_header_row_order_and_actual_gravity(self):
config = dict(self.config, parameters={'gravity': 9})
result = planet.prepare_surface(self.recipe()['surface'], self.recipe()['model'], config, self.root / 'sra')
lines = Path(result['topomap']).read_text().splitlines()
header = [int(value) for value in lines[0].split()]
baseline = Path(__file__).resolve().parents[1] / 'exoplasim/plasim/run/N032_surf_0129.sra'
with baseline.open() as stream:
expected = [int(value) for value in stream.readline().split()]
expected[2] = 0
self.assertEqual(header, expected)
data = np.fromstring(' '.join(lines[1:]), sep=' ').reshape(header[5], header[4])
with np.load(result['preview']) as archive:
land = archive['landmask'][0].astype(bool)
elevation = archive['elevation'][0]
np.testing.assert_allclose(data[land], elevation[land] * 9, rtol=2e-6)
self.assertTrue(np.all(data[~land] == 0))
with Path(result['landmap']).open() as stream:
self.assertEqual(int(stream.readline().split()[0]), 172)
def test_explicit_overrides_and_nullable_gravity(self):
recipe = self.recipe()
recipe['parameters'] = {'flux': 900, 'gravity': None}
result = planet.generate_planet(recipe, self.config, self.root / 'overrides')
self.assertEqual(result['spec']['parameters']['flux'], 900)
self.assertIsNone(result['spec']['parameters']['gravity'])
self.assertTrue(validate_spec(result['spec'], self.config)['ok'])
if __name__ == '__main__':
unittest.main()