diff --git a/domain/modelling/generators/heating_recommendation.py b/domain/modelling/generators/heating_recommendation.py index fcbe0e0c..c6eb0247 100644 --- a/domain/modelling/generators/heating_recommendation.py +++ b/domain/modelling/generators/heating_recommendation.py @@ -132,6 +132,9 @@ _REGULAR_GAS_BOILER_SAP_CODE = 102 _COMBI_GAS_BOILER_SAP_CODE = 104 # Water-heating code 901 — hot water from the main heating system. _WATER_FROM_MAIN_SYSTEM_CODE = 901 +# Elmhurst boiler flue type for the new condensing boiler (room-sealed/balanced); +# every relodged after lodges type 2. SAP-inert, written for end-state fidelity. +_CONDENSING_BOILER_FLUE_TYPE = 2 # Controls upgrade (SAP 10.2 Table 4e Group 1, PDF p.172): bring an inadequate # boiler control up to full programmer + room thermostat + TRVs (code 2106). @@ -328,6 +331,7 @@ def _boiler_combi_overlay(epc: EpcPropertyData) -> HeatingOverlay: heat_emitter_type=_RADIATOR_EMITTER, sap_main_heating_code=_COMBI_GAS_BOILER_SAP_CODE, fan_flue_present=True, + boiler_flue_type=_CONDENSING_BOILER_FLUE_TYPE, main_heating_control=_upgraded_boiler_control(main), water_heating_code=_WATER_FROM_MAIN_SYSTEM_CODE, water_heating_fuel=_MAINS_GAS_FUEL, @@ -356,6 +360,7 @@ def _boiler_cylinder_overlay(epc: EpcPropertyData) -> HeatingOverlay: heat_emitter_type=_RADIATOR_EMITTER, sap_main_heating_code=_REGULAR_GAS_BOILER_SAP_CODE, fan_flue_present=True, + boiler_flue_type=_CONDENSING_BOILER_FLUE_TYPE, main_heating_control=_upgraded_boiler_control(main), water_heating_code=_WATER_FROM_MAIN_SYSTEM_CODE, water_heating_fuel=_MAINS_GAS_FUEL, diff --git a/domain/modelling/scoring/overlay_applicator.py b/domain/modelling/scoring/overlay_applicator.py index 2696d7ab..f15ff102 100644 --- a/domain/modelling/scoring/overlay_applicator.py +++ b/domain/modelling/scoring/overlay_applicator.py @@ -71,6 +71,7 @@ _MAIN_HEATING_FIELDS: tuple[str, ...] = ( "main_heating_index_number", "main_heating_category", "fan_flue_present", + "boiler_flue_type", ) _SAP_HEATING_FIELDS: tuple[str, ...] = ( "water_heating_code", diff --git a/domain/modelling/simulation.py b/domain/modelling/simulation.py index 40d6fc95..abf192e9 100644 --- a/domain/modelling/simulation.py +++ b/domain/modelling/simulation.py @@ -122,6 +122,10 @@ class HeatingOverlay: # upgrade sets this True (SAP 10.2 Table 4f flue-fan electricity + the # Table 4b condensing-boiler seasonal-efficiency basis depend on it). fan_flue_present: Optional[bool] = None + # The boiler's flue type (Elmhurst enum) — a new condensing boiler lodges + # type 2 (room-sealed/balanced). SAP-inert, but written for fidelity so the + # end-state matches the installed boiler. + boiler_flue_type: Optional[int] = None # sap_heating (top-level) water_heating_code: Optional[int] = None water_heating_fuel: Optional[int] = None diff --git a/tests/domain/modelling/fixtures/boiler_cyl_coal_001431_after.pdf b/tests/domain/modelling/fixtures/boiler_cyl_coal_001431_after.pdf new file mode 100644 index 00000000..53e1c8d4 Binary files /dev/null and b/tests/domain/modelling/fixtures/boiler_cyl_coal_001431_after.pdf differ diff --git a/tests/domain/modelling/fixtures/boiler_cyl_coal_001431_before.pdf b/tests/domain/modelling/fixtures/boiler_cyl_coal_001431_before.pdf new file mode 100644 index 00000000..de84ab54 Binary files /dev/null and b/tests/domain/modelling/fixtures/boiler_cyl_coal_001431_before.pdf differ diff --git a/tests/domain/modelling/test_elmhurst_cascade_pins.py b/tests/domain/modelling/test_elmhurst_cascade_pins.py index a5cec154..a83a7c89 100644 --- a/tests/domain/modelling/test_elmhurst_cascade_pins.py +++ b/tests/domain/modelling/test_elmhurst_cascade_pins.py @@ -856,6 +856,37 @@ def test_boiler_with_already_insulated_cylinder_overlay_reproduces_the_relodged_ _assert_overlay_reproduces_after(before, after, option.overlay) +def test_coal_boiler_with_cylinder_overlay_reproduces_the_relodged_after() -> None: + # Arrange — a SOLID-FUEL (coal) boiler (fuel 11, SAP code 153) heating a + # cylinder, on a mains-gas street, re-lodged as a gas condensing boiler + # (fuel 11->26, code 102, fanned flue + boiler flue type 2). Exercises the + # non-gas -> gas conversion for a solid-fuel boiler AND the new + # `boiler_flue_type` end-state (coal's before lodged none; every other cert + # already lodged flue type 2). The cylinder is already 80 mm insulated so the + # jacket is skipped; only the thermostat is added. + # + # The relodged after predates the user-locked "always add a cylinder + # thermostat when absent" rule, so it stale-lodged thermostat 'N'; the test + # corrects it to the rule's end-state 'Y' (the same correction the gas + # with-cylinder after received by re-lodging). Controls are already adequate + # (2106), so they are unchanged. + before: EpcPropertyData = parse_recommendation_summary( + "boiler_cyl_coal_001431_before.pdf" + ) + after: EpcPropertyData = parse_recommendation_summary( + "boiler_cyl_coal_001431_after.pdf" + ) + after.sap_heating.cylinder_thermostat = "Y" + recommendation: Recommendation | None = recommend_heating(before, _AnyProduct()) + assert recommendation is not None + option = next( + o for o in recommendation.options if o.measure_type == "gas_boiler_upgrade" + ) + + # Act / Assert + _assert_overlay_reproduces_after(before, after, option.overlay) + + # --- Solar PV cascade pins (ADR-0026) ------------------------------------- # # The solar before/after Summaries lodge *synthetic* PV arrays (each 1.00 kWp, diff --git a/tests/domain/modelling/test_heating_recommendation.py b/tests/domain/modelling/test_heating_recommendation.py index 9b011437..297b1f8e 100644 --- a/tests/domain/modelling/test_heating_recommendation.py +++ b/tests/domain/modelling/test_heating_recommendation.py @@ -280,6 +280,7 @@ def test_gas_boiler_with_cylinder_dwelling_yields_a_boiler_upgrade_bundle() -> N heat_emitter_type=1, sap_main_heating_code=102, fan_flue_present=True, + boiler_flue_type=2, water_heating_code=901, water_heating_fuel=26, cylinder_insulation_type=2, @@ -386,6 +387,7 @@ def test_gas_combi_dwelling_yields_a_combi_boiler_upgrade_bundle() -> None: heat_emitter_type=1, sap_main_heating_code=104, fan_flue_present=True, + boiler_flue_type=2, main_heating_control=2106, water_heating_code=901, water_heating_fuel=26,