from pathlib import Path import sys import pytest SCRIPTS = Path(__file__).resolve().parents[1] / "scripts" sys.path.insert(0, str(SCRIPTS)) from thermal_demand import ( # noqa: E402 CapacityInputs, annual_heat_mwh, captured_heat_kw, heat_pump_case, size_modules, ) def test_15kw_module_produces_about_100mwh_captured_heat(): heat_kw = captured_heat_kw(15, load_factor=0.85, capture_factor=0.90) assert annual_heat_mwh(heat_kw) == pytest.approx(100.521) def test_heat_pump_electricity_is_explicit(): result = heat_pump_case(source_heat_kw=90, heating_cop=3) assert result.delivered_heat_kw == pytest.approx(135) assert result.heat_pump_input_kw == pytest.approx(45) def test_capacity_rounds_down_to_15kw_modules(): result = size_modules( CapacityInputs( contracted_compute_kw=400, verified_grid_headroom_kw=350, conservative_base_heat_kw=210, equipment_site_limit_kw=500, load_factor=0.85, capture_factor=0.90, initial_heat_fraction=0.70, module_kw=15, ) ) assert result.eligible_modules == 12 assert result.eligible_it_kw == 180 assert result.limiting_gate == "heat" @pytest.mark.parametrize( "field", [ "contracted_compute_kw", "verified_grid_headroom_kw", "conservative_base_heat_kw", "equipment_site_limit_kw", ], ) def test_missing_capacity_gate_means_zero_eligible_modules(field): values = { "contracted_compute_kw": 100, "verified_grid_headroom_kw": 100, "conservative_base_heat_kw": 100, "equipment_site_limit_kw": 100, } values[field] = None result = size_modules(CapacityInputs(**values)) assert result.eligible_modules == 0 assert result.eligible_it_kw == 0 assert result.limiting_gate == "missing_gate"