Slice 101c: HP cert 0380 — Table 4f cat-4 pumps/fans = 0

SAP 10.2 Table 4f lists annual pumps + fans electricity consumption
by main heating category. The cascade's
`_PUMPS_FANS_KWH_BY_MAIN_CATEGORY` only had cat-2 (gas-fired
boilers, 160 kWh = 115 pump + 45 flue fan) — HP certs (cat 4) fell
through to the 130 kWh/yr DEFAULT.

Heat pumps have NO additional pumps/fans contribution per Table 4f:
the HP system's circulation pump + fans are already incorporated
into the seasonal COP. Worksheet line (249) "Pumps, fans and
electric keep-hot" shows 0.0000 kWh for cert 0380 (ASHP).

Added `4: 0.0`. Effect on cert 0380 API path: pumps_fans cost
£17.15 → £0.00 (matches worksheet); total cost £171.36 → £154.21
(worksheet £206.75; remaining Δ -£52 is dominated by the hot-water
cascade gap which is the next slice — cylinder storage + primary
loss + HP HW COP + separate electric shower line all need work).

No golden cert residual shifts (cohort certs are all gas boilers).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-05-26 22:44:09 +00:00 committed by Jun-te Kim
parent a736db3f4a
commit 23e35da614
2 changed files with 33 additions and 0 deletions

View file

@ -650,6 +650,34 @@ def test_api_0380_heat_pump_no_secondary_heating_per_table_11() -> None:
assert result.secondary_heating_fuel_kwh_per_yr == 0.0
def test_api_0380_heat_pump_no_pumps_fans_kwh_per_table_4f() -> None:
# Arrange — SAP 10.2 Table 4f lists annual pumps + fans electricity
# consumption by main heating category. Gas-fired boilers (cat 2)
# use 160 kWh/yr (115 central heating pump + 45 flue fan). Heat
# pumps (cat 4) have NO additional pumps/fans contribution because
# the HP system's circulation pump and fans are already
# incorporated into the system COP.
#
# The cascade's `_PUMPS_FANS_KWH_BY_MAIN_CATEGORY` dict only had a
# cat-2 entry; cat-4 HP certs fell through to the DEFAULT 130
# kWh/yr (~£17 at 13.19 p/kWh) — the worksheet line (249) "Pumps,
# fans and electric keep-hot" shows 0.0000 kWh/yr for cert 0380.
doc = json.loads(_API_0380_JSON.read_text())
epc = EpcPropertyDataMapper.from_api_response(doc)
# Act
from domain.sap10_calculator.calculator import calculate_sap_from_inputs
from domain.sap10_calculator.rdsap.cert_to_inputs import (
cert_to_inputs, SAP_10_2_SPEC_PRICES,
)
result = calculate_sap_from_inputs(
cert_to_inputs(epc, prices=SAP_10_2_SPEC_PRICES)
)
# Assert
assert result.pumps_fans_kwh_per_yr == 0.0
def test_api_9501_room_in_roof_surfaces_populated() -> None:
# Arrange — cert 9501's API JSON lodges measured RR detail under
# `sap_room_in_roof.room_in_roof_details`: two gable walls

View file

@ -173,6 +173,11 @@ _DEFAULT_PUMPS_FANS_KWH_PER_YR: Final[float] = 130.0
# (Table 4f spec lines 7905-8076) — deferred until a fixture exercises.
_PUMPS_FANS_KWH_BY_MAIN_CATEGORY: Final[dict[int, float]] = {
2: 160.0, # Gas-fired boilers (115 pump + 45 flue fan)
4: 0.0, # Heat pumps — circulation pump + fans already in COP
# per SAP 10.2 Table 4f. Worksheet line (249) shows
# 0 kWh on cert 0380 (HP ASHP). Without this explicit
# entry HP certs fell through to the 130 kWh/yr DEFAULT
# and over-billed £17/yr at electricity rate.
}
# SAP10.2 Table 6d note 1: "average or unknown" overshading is the
# default for existing dwellings. RdSAP doesn't lodge a per-dwelling