diff --git a/packages/domain/src/domain/ml/tests/test_rdsap_uvalues.py b/packages/domain/src/domain/ml/tests/test_rdsap_uvalues.py index 1ac7e55f..571d27ab 100644 --- a/packages/domain/src/domain/ml/tests/test_rdsap_uvalues.py +++ b/packages/domain/src/domain/ml/tests/test_rdsap_uvalues.py @@ -1283,3 +1283,57 @@ def test_u_roof_matches_table16_for_every_cohort_description_thickness_pair( # Assert assert abs(u - expected_u) < 1e-4 + + +# ----- §5.12 formula cascade cohort pins (Floors) ----- +# +# u_floor is formula-driven (BS EN ISO 13370 + RdSAP10 §5.12) rather +# than table-lookup, so each pin asserts a per-geometry value derived +# by hand from the spec formula. Two cases from cert 0240 (main + +# extension) cover the dt < B and dt > B branches of the solid-floor +# branch; suspended-floor + Table 19 footnote (2) overrides land in +# follow-on slices when cohort coverage demands them. +# +# Hand-derivation for the first row (cert 0240 bp0): +# age J → Table 19 default insulation = 75 mm +# w = 0.3 m (default), g = 1.5, Rsi+Rse = 0.21, Rf = 0.001×75/0.035 = 2.143 +# dt = 0.3 + 1.5×(0.21 + 2.143) = 3.829 +# B = 2×97.72/36.45 = 5.362 → dt < B branch +# U = 2g·ln(πB/dt + 1)/(πB + dt) = 0.2447 → rounds to 0.24 +_FLOOR_FORMULA_COHORT_PINS: tuple[tuple[str, str, Optional[int], float, float, Optional[int], float], ...] = ( + # (description, age, construction, area_m2, perimeter_m, wall_thickness_mm, expected_u) + ("Solid, insulated (assumed)", "J", 1, 97.72, 36.45, None, 0.24), # cert 0240 bp0 (dt < B) + ("Solid, insulated (assumed)", "J", 1, 20.61, 13.45, None, 0.29), # cert 0240 bp1 (dt > B) +) + + +@pytest.mark.parametrize( + "description, age_band, construction, area_m2, perimeter_m, wall_thickness_mm, expected_u", + _FLOOR_FORMULA_COHORT_PINS, +) +def test_u_floor_matches_section_5_12_formula_for_cohort_geometry( + description: str, + age_band: str, + construction: Optional[int], + area_m2: float, + perimeter_m: float, + wall_thickness_mm: Optional[int], + expected_u: float, +) -> None: + # Arrange — inputs replicate what `heat_transmission_from_cert` feeds + # `u_floor` for the corresponding building part in the cohort. + + # Act + u = u_floor( + country=Country.ENG, + age_band=age_band, + construction=construction, + insulation_thickness_mm=None, + area_m2=area_m2, + perimeter_m=perimeter_m, + wall_thickness_mm=wall_thickness_mm, + description=description, + ) + + # Assert + assert abs(u - expected_u) < 1e-4