Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions data/era5_kipppunkte.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
year,temp_anomaly,ice_volume
1940,-0.109,34.91
1941,-0.102,35.31
1942,-0.098,34.13
1943,-0.065,34.66
1944,-0.093,34.74
1945,-0.061,35.15
1946,-0.031,34.5
1947,-0.109,33.8
1948,-0.045,34.82
1949,-0.053,33.97
1950,-0.018,33.14
1951,-0.063,33.95
1952,0.014,33.41
1953,-0.009,33.48
1954,0.021,32.62
1955,0.014,32.24
1956,-0.171,32.5
1957,-0.063,33.05
1958,0.038,31.8
1959,0.055,31.71
1960,0.005,31.85
1961,0.023,32.2
1962,0.06,31.75
1963,0.067,31.59
1964,-0.004,30.77
1965,0.012,31.15
1966,0.031,31.84
1967,0.003,29.88
1968,0.104,30.91
1969,0.094,30.37
1970,0.156,29.66
1971,-0.009,29.19
1972,0.139,28.48
1973,0.09,29.08
1974,0.075,29.06
1975,0.135,29.59
1976,0.159,27.86
1977,0.11,27.49
1978,0.223,27.35
1979,0.184,27.73
1980,0.167,26.94
1981,0.122,26.26
1982,0.22,26.73
1983,0.348,26.23
1984,0.314,26.04
1985,0.385,26.11
1986,0.358,24.87
1987,0.418,25.27
1988,0.46,24.77
1989,0.525,24.3
1990,0.526,24.24
1991,0.421,23.31
1992,0.465,24.28
1993,0.545,23.6
1994,0.375,23.3
1995,0.573,22.36
1996,0.524,22.32
1997,0.687,21.47
1998,0.58,22.36
1999,0.603,21.17
2000,0.66,20.41
2001,0.691,20.1
2002,0.755,20.38
2003,0.863,20.19
2004,0.832,19.06
2005,0.767,19.54
2006,0.903,18.2
2007,0.881,18.99
2008,0.938,18.71
2009,0.873,17.75
2010,0.819,17.77
2011,0.906,18.33
2012,0.905,17.13
2013,0.872,16.42
2014,1.006,16.68
2015,1.101,15.89
2016,0.971,15.78
2017,1.093,15.44
2018,1.044,15.4
2019,1.115,14.82
2020,1.21,14.41
2021,1.175,14.81
2022,1.197,13.22
2023,1.213,13.74
2 changes: 2 additions & 0 deletions src/genesis_os/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
"PhaseMatrix",
"RuntimeEngine",
"__version__",
"utac_core",
]

from genesis_os.core.crep import CREPEvaluator
from genesis_os.core.orchestrator import GenesisOS
from genesis_os.core.phase import PhaseMatrix
from genesis_os.plugins.adapters import utac_core
from genesis_os.runtime.emergence import CosmicWebSimulator
from genesis_os.runtime.engine import RuntimeEngine
29 changes: 29 additions & 0 deletions src/genesis_os/plugins/adapters/utac_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from __future__ import annotations

import math
from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
Expand All @@ -17,6 +18,34 @@
_ENGINE = None


def compute_tension_metric(temp_anomaly: float, ice_volume: float) -> float:
"""Compute UTAC tension metric from ERA5 climate observables.

Maps temperature anomaly and Arctic ice volume to a scalar tension value
consistent with the UTAC-Logistic framework. Higher temperature anomalies
and lower ice volumes yield higher tension.

.. math::
C = \\exp\\!\\left(-\\frac{T^2}{2\\sigma^2}\\right), \\quad
\\Gamma = C \\cdot \\exp\\!\\left(-\\frac{(1-C)^2}{2\\sigma^2}\\right), \\quad
\\mathcal{T} = (1 - C + \\Gamma)\\,\\bigl(1 + \\tfrac{1}{1 + V}\\bigr)

Args:
temp_anomaly: Global mean temperature anomaly in °C.
ice_volume: Arctic sea ice volume in 10³ km³ (PIOMAS-style).

Returns:
Tension metric T ≥ 0.
"""
sigma = 1.5
coherence = math.exp(-(temp_anomaly / sigma) ** 2 / 2.0)
gamma = coherence * math.exp(-((1.0 - coherence) ** 2) / (2.0 * sigma**2))
# Tension = lost coupling (1 - gamma) amplified by ice-volume stress.
# As temp_anomaly rises, gamma falls and tension grows; lower ice → higher stress.
ice_stress = 1.0 / (1.0 + max(0.0, ice_volume))
return float((1.0 - gamma) * (1.0 + ice_stress))


def plugin_fn(state: GenesisState) -> dict[str, Any]:
"""Override internal UTAC with external utac-core step."""
if not _AVAILABLE or state.crep is None:
Expand Down
27 changes: 27 additions & 0 deletions tests/unit/test_adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,3 +401,30 @@ def test_exception(self, state_with_crep: GenesisState) -> None:
patch.object(utac_core, "_ENGINE", mock_engine):
result = utac_core.plugin_fn(state_with_crep)
assert result["utac_entropy"] is None

def test_compute_tension_metric_returns_float(self) -> None:
result = utac_core.compute_tension_metric(1.2, 15.0)
assert isinstance(result, float)
assert result >= 0.0

def test_compute_tension_metric_zero_anomaly(self) -> None:
# Zero anomaly → gamma=1 → minimum tension (close to 0)
result = utac_core.compute_tension_metric(0.0, 30.0)
assert result == pytest.approx(0.0, abs=1e-9)

def test_compute_tension_metric_high_anomaly(self) -> None:
# High anomaly produces higher tension than zero anomaly at same ice
low = utac_core.compute_tension_metric(0.0, 20.0)
high = utac_core.compute_tension_metric(3.0, 20.0)
assert high > low

def test_compute_tension_metric_ice_stress(self) -> None:
# Lower ice volume → higher tension (more ice stress)
plenty_ice = utac_core.compute_tension_metric(1.0, 30.0)
low_ice = utac_core.compute_tension_metric(1.0, 5.0)
assert low_ice > plenty_ice

def test_compute_tension_metric_top_level_import(self) -> None:
from genesis_os import utac_core as uc
result = uc.compute_tension_metric(1.38, 12.8)
assert isinstance(result, float)
Loading