From fb14f038730192d1d2d2db9fe75c904e86bda394 Mon Sep 17 00:00:00 2001 From: Jun-te Kim Date: Thu, 11 Jun 2026 11:55:46 +0000 Subject: [PATCH] =?UTF-8?q?Map=20Not-Defined=20glazing=20code=20to=20a=20v?= =?UTF-8?q?alid=20type=20for=20windowless=2018.0=20certs=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) --- datatypes/epc/domain/mapper.py | 19 ++++++++++++++++--- datatypes/epc/schema/rdsap_schema_18_0.py | 4 +++- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/datatypes/epc/domain/mapper.py b/datatypes/epc/domain/mapper.py index 688e5ebe..a2f436a6 100644 --- a/datatypes/epc/domain/mapper.py +++ b/datatypes/epc/domain/mapper.py @@ -3009,6 +3009,12 @@ def _synthesise_20_0_0_sap_windows(schema: RdSapSchema20_0_0) -> List[SapWindow] ] +# ADR-0028: multiple_glazing_type "ND" (Not Defined, 69/1000 18.0 certs) has no +# cascade mapping — treat as the DG-modal default (cascade code 2 → daylight g_L +# 0.80, matching the calculator's `_G_LIGHT_DEFAULT` for unknown glazing). +_RDSAP18_ND_GLAZING_TYPE: int = 2 + + def _synthesise_18_0_sap_windows(schema: RdSapSchema18_0) -> List[SapWindow]: """ADR-0028 Reduced-Field Synthesis of `sap_windows` for an 18.0 cert. @@ -3025,15 +3031,22 @@ def _synthesise_18_0_sap_windows(schema: RdSapSchema18_0) -> List[SapWindow]: _RDSAP20_GLAZING_RATIO * float(schema.total_floor_area) * band_multiplier ) per_window_area = total_area / len(_RDSAP20_SYNTH_ORIENTATIONS) + # ADR-0028: 18.0 glazed_type codes 1-8 are identical to 20.0.0's (verified + # against epc_codes.csv), so reuse the verified cascade for integer codes; + # the "ND" string falls back to the DG-modal default. + mgt = schema.multiple_glazing_type + glazing_type = ( + _api_cascade_glazing_type(mgt) + if isinstance(mgt, int) + else _RDSAP18_ND_GLAZING_TYPE + ) return [ SapWindow( frame_material=None, glazing_gap=0, orientation=orientation, window_type=0, - # ADR-0028: 18.0 glazed_type codes 1-8+ND are identical to 20.0.0's - # (verified against epc_codes.csv), so reuse the verified cascade. - glazing_type=_api_cascade_glazing_type(schema.multiple_glazing_type), + glazing_type=glazing_type, window_width=per_window_area, window_height=1.0, draught_proofed=False, diff --git a/datatypes/epc/schema/rdsap_schema_18_0.py b/datatypes/epc/schema/rdsap_schema_18_0.py index 08e008db..b9e98154 100644 --- a/datatypes/epc/schema/rdsap_schema_18_0.py +++ b/datatypes/epc/schema/rdsap_schema_18_0.py @@ -241,7 +241,9 @@ class RdSapSchema18_0: energy_rating_current: int lighting_cost_current: CostAmount main_heating_controls: List[EnergyElement] - multiple_glazing_type: int + # ADR-0028: lodged as an int code (1-7) or the string "ND" (Not Defined, + # 69/1000) — widen so both parse; the synthesis maps "ND" to a default. + multiple_glazing_type: Union[int, str] open_fireplaces_count: int has_hot_water_cylinder: str heating_cost_potential: CostAmount