From ed1dea2639b1191421de3986483aedcc14067a12 Mon Sep 17 00:00:00 2001 From: godosa Date: Wed, 7 Oct 2026 00:01:14 +0200 Subject: worldhistory: initial public history --- tests/helpers.py | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 tests/helpers.py (limited to 'tests/helpers.py') diff --git a/tests/helpers.py b/tests/helpers.py new file mode 100644 index 0000000..28b6266 --- /dev/null +++ b/tests/helpers.py @@ -0,0 +1,68 @@ +import functools + +import numpy as np + +from worldhistory.world import World, neighbours_from_ids + +DEFAULTS = dict(ocean=False, elevation_m=100.0, T_mean=15.0, P_ann=1000.0, holdridge=20, landform=1, river=False, + strahler=0, lake=False, ice=0, coal_potential=False, iron_potential=False, vent_potential=0.0, + seabed_type=0, lithology=1, ground=0, gravity_g=1.0, o2_fraction=0.21, pressure_bar=1.0, + bottom_temp_c=2.0, plate=0) + + +def fields(n, **over): + out = {} + for k, v in {**DEFAULTS, **over}.items(): + a = np.asarray(v) + out[k] = np.broadcast_to(a, (n,)).copy() if a.ndim == 0 else a.copy() + return out + + +def line_world(n, spacing_km=100.0, radius_km=6371.0, **over): + """Cells on the equator in a row, each linked to the next: 1-D worlds with hand-checkable answers.""" + lon = np.arange(n) * np.degrees(spacing_km / radius_km) + lat = np.zeros(n) + xyz = np.stack([np.cos(np.radians(lon)), np.sin(np.radians(lon)), np.zeros(n)], 1) + nb = np.full((n, 6), -1, np.int64) + nb[1:, 0] = np.arange(n - 1) + nb[:-1, 1] = np.arange(1, n) + return World(nb=nb, lat=lat, lon=lon, xyz=xyz, area=np.full(n, spacing_km ** 2), radius_km=radius_km, + base=fields(n, **over)) + + +@functools.lru_cache(maxsize=4) +def _h3_grid(res): + import h3.api.basic_int as h3 + ids = sorted(c for r0 in h3.get_res0_cells() for c in h3.cell_to_children(r0, res)) + ll = np.array([h3.cell_to_latlng(c) for c in ids]) + area = np.array([h3.cell_area(c, unit="rads^2") for c in ids]) + return np.array(ids, np.uint64), ll, area + + +def globe_world(res=1, radius_km=6371.0): + """A whole H3 globe (res 1 = 842 cells) with default fields; tests edit world.base afterwards.""" + ids, ll, area = _h3_grid(res) + lat, lon = ll[:, 0].copy(), ll[:, 1].copy() + la, lo = np.radians(lat), np.radians(lon) + xyz = np.stack([np.cos(la) * np.cos(lo), np.cos(la) * np.sin(lo), np.sin(la)], 1) + return World(nb=neighbours_from_ids(ids), lat=lat, lon=lon, xyz=xyz, area=area * radius_km ** 2, + radius_km=radius_km, base=fields(len(ids))) + + +from worldhistory.config import parse_history, parse_race + + +def make_race(id="a", **over): + """A land race with density 1/km² at q=1, growth 0.1/step, no Allee, founder 1, no mobility; sections override.""" + d = {"id": id, + "demography": {"density": 1.0, "growth": 0.1, "allee": 0.0, "founder": 1.0, "mobility": 0.0}, + "habitat": {"realm": "land", "terms": [{"p": "land", "w": 1.0}]}} + for k, v in over.items(): + d[k] = {**d.get(k, {}), **v} if isinstance(v, dict) and isinstance(d.get(k), dict) else v + return parse_race(d, f"test:{id}") + + +def make_history(**over): + d = {"run": {"years": 100, "step": 10, "snapshot_every": 50, "seed": 1}} + d.update(over) + return parse_history(d, "test:history") -- cgit