diff --git a/domain/epc/property_overlays/roof_type_overlay.py b/domain/epc/property_overlays/roof_type_overlay.py index aadcc3878..a2ba1811b 100644 --- a/domain/epc/property_overlays/roof_type_overlay.py +++ b/domain/epc/property_overlays/roof_type_overlay.py @@ -27,6 +27,8 @@ from datatypes.epc.domain.epc_property_data import BuildingPartIdentifier 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") def roof_overlay_for( @@ -49,8 +51,18 @@ def _overlay_for(roof_type_value: str) -> Optional[BuildingPartOverlay]: if match is not None: return BuildingPartOverlay(roof_insulation_thickness=int(match.group(1))) if roof_type_value.startswith("Flat,"): - # Flat roof: U-value is the age-band default; flag the shape and let the - # age-band overlay drive `_FLAT_ROOF_BY_AGE` (ADR-0033). + flat_depth = _FLAT_MM.search(roof_type_value) + if flat_depth is not None: + # A flat roof with a known depth: RdSAP 10 Table 16 col (1) ("joists at + # ceiling level and flat roof") scores it by thickness, so carry the + # depth (the calculator routes flat + thickness through Table 16, not + # the age-band default). ADR-0041. + return BuildingPartOverlay( + roof_construction_type="Flat", + roof_insulation_thickness=int(flat_depth.group(1)), + ) + # Flat roof with no stated depth: U-value is the age-band default; flag the + # shape and let the age-band overlay drive `_FLAT_ROOF_BY_AGE` (ADR-0033). return BuildingPartOverlay(roof_construction_type="Flat") if roof_type_value == "Pitched, Unknown loft insulation": # Unknown loft depth: U-value is the pitched age-band default. Assert the