from pathlib import Path import sys import pandas as pd SCRIPTS = Path(__file__).resolve().parents[1] / "scripts" sys.path.insert(0, str(SCRIPTS)) from heat_demand_sizing import size_heat_sinks # noqa: E402 def test_only_complete_sink_gates_receive_modules(): sinks = pd.DataFrame( [ { "heat_sink_id": "hospital-1", "sink_class": "hospital", "base_load_mw": 0.210, "supply_temp_c": 70, "evidence_state": "metered_direct", }, { "heat_sink_id": "greenhouse-1", "sink_class": "greenhouse", "base_load_mw": 0.080, "supply_temp_c": 45, "evidence_state": "modeled_estimated", }, ] ) gates = pd.DataFrame( [ { "heat_sink_id": "hospital-1", "contracted_compute_kw": 400, "verified_grid_headroom_kw": 350, "equipment_site_limit_kw": 500, } ] ) result = size_heat_sinks(sinks, gates).set_index("heat_sink_id") assert result.loc["hospital-1", "eligible_modules"] == 12 assert result.loc["hospital-1", "eligible_it_kw"] == 180 assert result.loc["hospital-1", "direct_or_heat_pump"] == "heat_pump" assert result.loc["greenhouse-1", "eligible_modules"] == 0 assert result.loc["greenhouse-1", "planning_status"] == "missing_gate" def test_heat_source_without_sink_is_not_sized(): sinks = pd.DataFrame( [ { "heat_sink_id": "hospital-1", "sink_class": "hospital", "base_load_mw": 0.210, "supply_temp_c": 70, "evidence_state": "metered_direct", } ] ) gates = pd.DataFrame( columns=[ "heat_sink_id", "contracted_compute_kw", "verified_grid_headroom_kw", "equipment_site_limit_kw", ] ) result = size_heat_sinks(sinks, gates) assert "wastewater-source-1" not in result["heat_sink_id"].tolist() def test_proxy_without_demand_remains_unsized(): sinks = pd.DataFrame( [ { "heat_sink_id": "industrial-proxy", "sink_class": "industrial", "base_load_mw": float("nan"), "supply_temp_c": 90, "evidence_state": "proxy_indicator", } ] ) result = size_heat_sinks(sinks, pd.DataFrame()) assert result.loc[0, "planning_status"] == "unsized_proxy" assert result.loc[0, "eligible_modules"] == 0