diff --git a/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000474.py b/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000474.py index 19a2c65e..a605fda3 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000474.py +++ b/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000474.py @@ -64,11 +64,14 @@ def build_epc() -> EpcPropertyData: wall_thickness_measured=False, party_wall_construction=0, sap_floor_dimensions=[ + # Ext1 hangs off the main from the first storey upward — its + # lowest dimension is an exposed timber floor (Table 20). SapFloorDimension( room_height_m=2.81, # lowest of ext, internal total_floor_area_m2=15.04, party_wall_length_m=3.56, heat_loss_perimeter_m=8.46, floor=0, + is_exposed_floor=True, ), SapFloorDimension( room_height_m=3.13, # = 2.88 + 0.25 @@ -163,3 +166,18 @@ LINE_31_TOTAL_EXTERNAL_AREA_M2: float = 153.3900 LINE_33_FABRIC_HEAT_LOSS_W_PER_K: float = 209.1084 LINE_36_THERMAL_BRIDGING_W_PER_K: float = 23.0085 LINE_37_TOTAL_FABRIC_HEAT_LOSS_W_PER_K: float = 232.1169 + +# §3 windows + doors — values from the Elmhurst worksheet §3 table. +# Two window types share the dwelling: +# Type 1 (post-2002 double-glazed, PVC, g=0.72): 6.22 m² at raw U=2.0, +# U_eff=1.8519 +# Type 2 (pre-2002 double-glazed, PVC, g=0.76): 5.50 m² at raw U=2.8, +# U_eff=2.5180 +# Worksheet windows_w_per_k = 25.3675. Aggregating to a single area- +# weighted raw U with the curtain-resistance transform applied reproduces +# the total to better than 0.05 W/K: +# U_eff_target = 25.3675 / 11.72 = 2.1645 +# raw U = 1/(1/2.1645 - 0.04) ≈ 2.37 +WINDOW_TOTAL_AREA_M2: float = 11.72 +WINDOW_AVG_RAW_U_VALUE: float = 2.37 +DOOR_COUNT: int = 2 # cascade default 1.85 m²/door → 3.70 m² matches worksheet diff --git a/packages/domain/src/domain/sap/worksheet/tests/test_heat_transmission.py b/packages/domain/src/domain/sap/worksheet/tests/test_heat_transmission.py index ea4e31df..c2e48d72 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/test_heat_transmission.py +++ b/packages/domain/src/domain/sap/worksheet/tests/test_heat_transmission.py @@ -1179,6 +1179,34 @@ def test_section_3_non_rr_line_31_and_36_match_elmhurst_worksheet( ) +def test_section_3_line_33_and_line_37_match_elmhurst_worksheet_000474() -> None: + """Full §3 fabric heat loss for Elmhurst U985-0001-000474. Mid-terrace + with 3 building parts (Main + 2 extensions). Ext1 is the exposed-timber + upper floor (same shape as 000490 Ext1). Two window types share an + area-weighted raw U-value when aggregated (post-2002 raw 2.0 mixed + with pre-2002 raw 2.8); reproducing the worksheet's per-type sum of + 25.37 W/K to 0.1 W/K is sufficient given the curtain-resistance + transform is non-linear.""" + # Arrange + epc = _w000474.build_epc() + + # Act + result = heat_transmission_from_cert( + epc, + window_total_area_m2=_w000474.WINDOW_TOTAL_AREA_M2, + window_avg_u_value=_w000474.WINDOW_AVG_RAW_U_VALUE, + door_count=_w000474.DOOR_COUNT, + ) + + # Assert + assert result.fabric_heat_loss_w_per_k == pytest.approx( + _w000474.LINE_33_FABRIC_HEAT_LOSS_W_PER_K, abs=0.1 + ) + assert result.total_w_per_k == pytest.approx( + _w000474.LINE_37_TOTAL_FABRIC_HEAT_LOSS_W_PER_K, abs=0.1 + ) + + def test_section_3_line_33_and_line_37_match_elmhurst_worksheet_000490() -> None: """Full §3 fabric heat loss for Elmhurst U985-0001-000490. Once the suspended/exposed floor routes are wired and the cert lodges the