From e384e37f5fafd5316dc38365454640dad1856533 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Thu, 23 Jul 2026 13:26:48 +0000 Subject: [PATCH] =?UTF-8?q?Carry=20the=20sloping-ceiling=20insulation=20de?= =?UTF-8?q?pth=20into=20the=20overlay=20=F0=9F=9F=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- .../epc/property_overlays/roof_type_overlay.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/domain/epc/property_overlays/roof_type_overlay.py b/domain/epc/property_overlays/roof_type_overlay.py index bf47c67cd..9fa8f3024 100644 --- a/domain/epc/property_overlays/roof_type_overlay.py +++ b/domain/epc/property_overlays/roof_type_overlay.py @@ -29,6 +29,9 @@ from domain.modelling.simulation import BuildingPartOverlay, EpcSimulation _LOFT_MM = re.compile(r"(\d+)\+?\s*mm loft insulation") # A flat roof carries no loft, so its depth reads "N mm insulation" (no "loft"). _FLAT_MM = re.compile(r"(\d+)\+?\s*mm insulation") +# A sloping ceiling's depth reads the same "N mm insulation" shape (no "loft"); +# the "sloping ceiling" prefix, not the suffix, distinguishes it from a flat roof. +_SLOPING_MM = re.compile(r"(\d+)\+?\s*mm insulation") def roof_overlay_for( @@ -53,9 +56,17 @@ def _overlay_for(roof_type_value: str) -> Optional[BuildingPartOverlay]: if roof_type_value.startswith("Pitched, sloping ceiling"): # ADR-0066: a slope-following ceiling (gov-API roof_construction 8) has no # loft void. Assert the sloping-ceiling shape so the calculator's - # `is_pitched_sloping_ceiling` drives the Table 18 col (3) age-band default - # ("as built"), never the loft ladder. Leave thickness None here. - return BuildingPartOverlay(roof_construction_type="Pitched, sloping ceiling") + # `is_pitched_sloping_ceiling` keys off "sloping ceiling" in the string. + # A known depth ("N mm insulation") rides into the overlay and scores on + # Table 17 col (1a) "insulated slope"; "as built" leaves thickness None so + # the Table 18 col (3) age-band default drives it. Never the loft ladder. + sloping_depth = _SLOPING_MM.search(roof_type_value) + return BuildingPartOverlay( + roof_construction_type="Pitched, sloping ceiling", + roof_insulation_thickness=( + int(sloping_depth.group(1)) if sloping_depth is not None else None + ), + ) if roof_type_value.startswith("Flat,"): flat_depth = _FLAT_MM.search(roof_type_value) if flat_depth is not None: