Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 14913@bnt-lap001 Assistant-Session: add7ef69-b901-4756-9a67-34cf1125d96f
76 lines
3.4 KiB
Python
76 lines
3.4 KiB
Python
"""Ecological resource classes across the adoption band (ASSEMBLY-WP-0007-T02).
|
||
|
||
Which class binds first per scenario (GADM-Sectors-Scope.md § 2)? Does organism growth bind
|
||
energy and sinks before materials (ParameterGrounding.md § 3 test)?
|
||
Classes: renewables Er (energy, land, water, biosphere), materials Ed, sinks Es; floors 0.20.
|
||
Materials with strict depletion (rm 0) or replenishment at rest today (rm "rest").
|
||
|
||
Usage: python3 -B simulations/gadm02/eco_classes.py
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
sys.dont_write_bytecode = True
|
||
|
||
import gadm05 as g5 # noqa: E402
|
||
import grounding as gr # noqa: E402
|
||
from scenarios import load_all # noqa: E402
|
||
|
||
OUT = Path(__file__).resolve().parent / "results"
|
||
ANCHORS = list(gr.BAND)
|
||
NAMES = {"Er": "renewables", "Ed": "materials", "Es": "sinks"}
|
||
FLOOR = g5.ECO_PARAMS["eco_floor"]
|
||
|
||
|
||
def crossing(rows: list[dict], k: str) -> str:
|
||
if rows[0][k] < FLOOR:
|
||
return "below at start"
|
||
for r in rows:
|
||
if r[k] < FLOOR:
|
||
return f"t {r['t']:.0f}"
|
||
return "—"
|
||
|
||
|
||
def main() -> None:
|
||
OUT.mkdir(exist_ok=True)
|
||
scs = load_all()
|
||
var = {a: gr.variant(gr.BAND[a]) for a in ANCHORS}
|
||
lines = ["# GADM-0.5-dev: ecological resource classes across the band", "",
|
||
"Generated by `simulations/gadm02/eco_classes.py` (ASSEMBLY-WP-0007-T02). Floors 0.20 per class.",
|
||
"Starting levels and loads: `gadm05.py` (priors from measured indicators). Crossing = first year",
|
||
"below the floor. t = 100 levels.", ""]
|
||
res = {}
|
||
for rm in (0.0, "rest"):
|
||
lines += [f"## Materials replenishment: {'none (strict depletion)' if rm == 0.0 else 'at rest today'}", "",
|
||
"| Scenario | Anchor | Er / Ed / Es t100 | renewables below floor | materials below floor | sinks below floor | lowest at t100 |",
|
||
"|---|---|---|---|---|---|---|"]
|
||
for sc in ("baseline", "generative_regime", "attention_oligopoly"):
|
||
for a in ANCHORS:
|
||
rows = g5.simulate_eco({**scs[sc]["params"], **var[a][0]}, {**scs[sc]["init"], **var[a][1]},
|
||
eco={"rm": rm})
|
||
f = rows[-1]
|
||
res[(rm, sc, a)] = rows
|
||
low = min(g5.ECO, key=lambda k: f[k])
|
||
lines.append(f"| {scs[sc]['title']} | {a} | {f['Er']:.2f} / {f['Ed']:.2f} / {f['Es']:.2f} | "
|
||
f"{crossing(rows, 'Er')} | {crossing(rows, 'Ed')} | {crossing(rows, 'Es')} | {NAMES[low]} |")
|
||
lines.append("")
|
||
lines += ["## Organism growth: class draw attributable to adoption speed (baseline, B4 − B1)", "",
|
||
"Relative change of each class between t 0 and t 50, B4 minus B1 (negative = organisms draw more).", "",
|
||
"| Materials replenishment | renewables | materials | sinks | order (most hit first) |", "|---|---|---|---|---|"]
|
||
for rm in (0.0, "rest"):
|
||
rel = {}
|
||
for k in g5.ECO:
|
||
r4, r1 = res[(rm, "baseline", "B4")], res[(rm, "baseline", "B1")]
|
||
rel[k] = (r4[5][k] / r4[0][k] - 1) - (r1[5][k] / r1[0][k] - 1)
|
||
order = " > ".join(NAMES[k] for k in sorted(rel, key=lambda k: rel[k]))
|
||
lines.append(f"| {'none' if rm == 0.0 else 'at rest'} | {rel['Er']:+.3f} | {rel['Ed']:+.3f} | {rel['Es']:+.3f} | {order} |")
|
||
lines.append("")
|
||
(OUT / "eco_classes.md").write_text("\n".join(lines))
|
||
print("\n".join(lines))
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|