mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-07-12 13:29:04 +00:00
Drag an air source heat pump's coherent companions 🟩
Heat pump drags category 4 + electricity (29). Meter stays single-rate: a heat pump does not imply an off-peak tariff the way storage/CPSU do (SAP §12 Rule 3 is conditional), so forcing Dual would mis-bill it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
848252e5d4
commit
0c12f70589
2 changed files with 15 additions and 6 deletions
|
|
@ -92,6 +92,12 @@ _ELECTRICITY_FUEL = 29
|
|||
_HOUSE_COAL_FUEL = 33
|
||||
_ELECTRIC_ROOM_HEATER_CODES = frozenset(range(691, 702))
|
||||
|
||||
# Heat pumps (SAP Table 4a 211-224 wet, 521-527 warm-air) are category 4 and
|
||||
# unambiguously electric (natural fuel 29). Modellable on the default code's SPF
|
||||
# without a PCDB index (ADR-0041).
|
||||
_HEAT_PUMP_CATEGORY = 4
|
||||
_HEAT_PUMP_CODES = frozenset(range(211, 225)) | frozenset(range(521, 528))
|
||||
|
||||
# SAP Table 4c full boiler-control code: programmer + room thermostat + TRVs. The
|
||||
# landlord names the boiler, not its controls — but a gas boiler installed under
|
||||
# modern Building Regs must carry compliant controls, and this overlay already
|
||||
|
|
@ -169,6 +175,8 @@ def _category_for(code: int) -> Optional[int]:
|
|||
as a room-heater system, not whatever category the replaced system carried."""
|
||||
if code in _SOLID_FUEL_ROOM_HEATER_CODES:
|
||||
return _ROOM_HEATER_CATEGORY
|
||||
if code in _HEAT_PUMP_CODES:
|
||||
return _HEAT_PUMP_CATEGORY
|
||||
return None
|
||||
|
||||
|
||||
|
|
@ -176,7 +184,7 @@ def _natural_fuel_for(code: int) -> Optional[int]:
|
|||
"""The fuel an archetype unambiguously implies (a coherent default), or None
|
||||
where the fuel is ambiguous and must come from the `main_fuel` override. A
|
||||
present `main_fuel` override wins by last-wins composition."""
|
||||
if code in _ELECTRIC_ROOM_HEATER_CODES:
|
||||
if code in _ELECTRIC_ROOM_HEATER_CODES or code in _HEAT_PUMP_CODES:
|
||||
return _ELECTRICITY_FUEL
|
||||
if code in _SOLID_FUEL_ROOM_HEATER_CODES:
|
||||
return _HOUSE_COAL_FUEL
|
||||
|
|
|
|||
|
|
@ -472,10 +472,11 @@ def test_air_source_heat_pump_decodes_to_the_default_ashp_code() -> None:
|
|||
|
||||
def test_air_source_heat_pump_drags_its_coherent_companions() -> None:
|
||||
# A heat pump is unambiguously electric (natural fuel 29) and SAP Table 4a
|
||||
# category 4, billed on an off-peak (Dual) meter (§12 Rule 3 lists heat pumps
|
||||
# 211-224). The overlay drags these code-derived companions so a system-only
|
||||
# override is self-coherent on a cert that lodged a different system
|
||||
# (ADR-0035 / ADR-0041).
|
||||
# category 4. Unlike storage/CPSU it does NOT imply an off-peak tariff (SAP
|
||||
# §12 Rule 3 is conditional, not forcing), so the coherent default meter is
|
||||
# single-rate — forcing Dual would assume an off-peak split it may not have
|
||||
# and mis-bill it. The overlay drags these code-derived companions so a
|
||||
# system-only override is self-coherent (ADR-0035 / ADR-0041).
|
||||
|
||||
# Act
|
||||
simulation = main_heating_overlay_for("Air source heat pump", 0)
|
||||
|
|
@ -486,4 +487,4 @@ def test_air_source_heat_pump_drags_its_coherent_companions() -> None:
|
|||
heating = simulation.heating
|
||||
assert heating.main_heating_category == 4
|
||||
assert heating.main_fuel_type == 29
|
||||
assert heating.meter_type == "Dual"
|
||||
assert heating.meter_type == "Single"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue