102 lines
5.2 KiB
Python
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()
|