diff --git a/domain/sap10_ml/rdsap_uvalues.py b/domain/sap10_ml/rdsap_uvalues.py index 725c7726..6b1e35fc 100644 --- a/domain/sap10_ml/rdsap_uvalues.py +++ b/domain/sap10_ml/rdsap_uvalues.py @@ -839,20 +839,21 @@ _ROOF_RAFTERS_BY_THICKNESS: Final[list[tuple[int, float]]] = [ (400, 0.14), ] -# Table 18 rafters column: pitched-roof "insulation at rafters" default U -# by age band when the thickness cannot be determined. RdSAP 10 §5.11 -# Table 18 (PDF p.45). Identical to the joist column (1) for bands A-G +# Table 18 column (2) "Pitched, insulation at rafters": pitched-roof default +# U by age band when the thickness cannot be determined. RdSAP 10 §5.11 +# Table 18 (PDF p.46). Identical to the joist column (1) for bands A-G # (2.30 → 0.40), then diverges higher (H 0.35 vs 0.30, I 0.35 vs 0.26, -# J/K 0.20 vs 0.16, L 0.18 vs 0.16). Unlike the loft-joist default this -# does NOT collapse to the optimistic 0.40 "assume modern retrofit" floor -# at old bands — a rafter cavity cannot be topped up from the loft, so an -# unknown-thickness rafter roof keeps the as-built age-band U (band F -# 0.68, band E 1.50, A-D 2.30). Worksheet-validated by simulated case 41 -# Ext3 (band F, R Rafters, As Built → P960 §3 (30) U=0.68). +# J/K 0.20 vs 0.16, L 0.18 vs 0.16) before converging to 0.15 at band M. +# Unlike the loft-joist default this does NOT collapse to the optimistic +# 0.40 "assume modern retrofit" floor at old bands — a rafter cavity cannot +# be topped up from the loft, so an unknown-thickness rafter roof keeps the +# as-built age-band U (band F 0.68, band E 1.50, A-D 2.30). Worksheet- +# validated by simulated case 41 Ext3 (band F, R Rafters, As Built → P960 +# §3 (30) U=0.68). _ROOF_RAFTERS_BY_AGE: Final[dict[str, float]] = { "A": 2.30, "B": 2.30, "C": 2.30, "D": 2.30, "E": 1.50, "F": 0.68, "G": 0.40, "H": 0.35, "I": 0.35, "J": 0.20, - "K": 0.20, "L": 0.18, "M": 0.18, + "K": 0.20, "L": 0.18, "M": 0.15, } # Table 18 column (3): flat-roof default U by age band when thickness unknown. diff --git a/domain/sap10_ml/tests/test_rdsap_uvalues.py b/domain/sap10_ml/tests/test_rdsap_uvalues.py index 8d670a2f..77de58eb 100644 --- a/domain/sap10_ml/tests/test_rdsap_uvalues.py +++ b/domain/sap10_ml/tests/test_rdsap_uvalues.py @@ -1265,6 +1265,25 @@ def test_u_roof_at_rafters_unknown_thickness_uses_table18_rafters_age_band() -> assert abs(band_c - 2.30) <= 0.001 +def test_u_roof_at_rafters_unknown_thickness_age_m_returns_0_15_per_table18() -> None: + # Arrange — RdSAP 10 Table 18 column (2) "Pitched, insulation at + # rafters" (PDF p.46): band M = 0.15 (footnote (1) only, no country + # variation — the whole M row converges to 0.15). The rafters column + # diverges above the joist column at H-L (0.35/0.35/0.20/0.20/0.18) + # but rejoins it at M = 0.15; the table previously carried 0.18 here. + + # Act + band_m = u_roof( + country=Country.ENG, + age_band="M", + insulation_thickness_mm=None, + insulation_at_rafters=True, + ) + + # Assert + assert abs(band_m - 0.15) <= 0.001 + + def test_u_roof_unknown_age_band_falls_back_to_mid_range() -> None: # Arrange — nothing known.