From b37be6327c1b7906438273a7aeb7592a321c988e Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Fri, 3 Jul 2026 10:13:19 +0000 Subject: [PATCH] =?UTF-8?q?ASHP=20sizing=20selects=20the=20smallest=20pump?= =?UTF-8?q?=20meeting=20the=20dwelling's=20design=20heat=20loss=20?= =?UTF-8?q?=F0=9F=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- .../generators/heating_recommendation.py | 25 +++++++++++++++++++ .../modelling/test_heating_recommendation.py | 17 ++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/domain/modelling/generators/heating_recommendation.py b/domain/modelling/generators/heating_recommendation.py index 70c33142c..dab016843 100644 --- a/domain/modelling/generators/heating_recommendation.py +++ b/domain/modelling/generators/heating_recommendation.py @@ -137,6 +137,31 @@ _ASHP_OVERLAY = HeatingOverlay( ) +# ASHP sizing ladder (ADR-0049): the Vaillant aroTHERM plus "& AI VIH RW" family, +# one representative PCDB Table 362 record per nominal size, ascending by rated +# max output (kW). The pump is sized to the dwelling's design heat loss so SAP +# 10.2 Appendix N reads the heat-pump efficiency near its PSR peak (~1.0), rather +# than a single fixed unit that is grossly undersized on high-heat-loss dwellings +# — where the PSR collapses and the ASHP scores at/below the resistance baseline. +# 110257 (the 5 kW rung) is the previously-fixed anchor, validated against the +# relodged after-cert. +_ASHP_SIZING_LADDER: tuple[tuple[float, int], ...] = ( + (3.76, 110249), # aroTHERM plus 3.5 kW + (4.37, 110257), # aroTHERM plus 5 kW + (6.40, 110265), # aroTHERM plus 7 kW + (7.93, 110273), # aroTHERM plus 10 kW + (11.48, 110281), # aroTHERM plus 12 kW +) + + +def select_ashp_pcdb_id(design_heat_loss_kw: float) -> int: + """The PCDB heat-pump record to install for a dwelling with + `design_heat_loss_kw`: the smallest ladder rung whose rated output meets the + load (PSR >= 1.0), capped at the largest rung when the load exceeds the + domestic aroTHERM plus range (ADR-0049).""" + raise NotImplementedError + + # --- Gas boiler upgrade (Heating/HW expansion): replace an existing wet boiler # with a modern gas condensing boiler. Validated against Elmhurst before/after # re-lodgements (cert 001431): the upgrade always targets mains gas — gas->gas diff --git a/tests/domain/modelling/test_heating_recommendation.py b/tests/domain/modelling/test_heating_recommendation.py index 366c51869..deca9ffad 100644 --- a/tests/domain/modelling/test_heating_recommendation.py +++ b/tests/domain/modelling/test_heating_recommendation.py @@ -7,7 +7,10 @@ later slices. Detection + pricing only; impact is produced by scoring (ADR-0016) from datatypes.epc.domain.epc_property_data import EpcPropertyData from domain.geospatial.planning_restrictions import PlanningRestrictions -from domain.modelling.generators.heating_recommendation import recommend_heating +from domain.modelling.generators.heating_recommendation import ( + recommend_heating, + select_ashp_pcdb_id, +) from domain.modelling.measure_type import MeasureType from domain.modelling.product import Product from domain.modelling.recommendation import Recommendation @@ -764,3 +767,15 @@ def test_boiler_upgrade_leaves_adequate_controls_unchanged() -> None: ).overlay.heating assert overlay is not None assert overlay.main_heating_control is None + + +def test_ashp_sizing_selects_the_smallest_pump_meeting_the_design_heat_loss() -> None: + # A 6 kW design heat loss needs a pump whose rated output covers it: the 7 kW + # aroTHERM plus (PCDB 110265, ~6.40 kW), the smallest ladder rung meeting the + # load — not the fixed 5 kW unit (4.37 kW) that would sit below the load and + # collapse SAP's Appendix-N PSR efficiency. + # Act + pcdb_id = select_ashp_pcdb_id(design_heat_loss_kw=6.0) + + # Assert — the 7 kW aroTHERM plus rung. + assert pcdb_id == 110265