mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
fix(hw): direct-acting electric boiler (191) → zero primary circuit loss
SAP 10.2 Table 3 (PDF p.160) names "Direct-acting electric boiler"
verbatim in the primary-loss zero list (alongside electric immersion,
combi, CPSU, integral-vessel heat pump). RdSAP 10 §12 (p.62) classifies
SAP code 191 as the direct-acting electric boiler. Its cylinder is
immersion-heated with no primary pipework, so no primary circuit loss
applies — but `_primary_loss_applies` had no 191 branch, so a 191 main
(main_heating_category 2, "Boiler and radiators, electric") fell through
to the cat-{1,2} boiler branch and accrued ~1177 kWh/yr of phantom
primary loss on the electric-flat segment.
Validated against the cert-2474 worksheet: §4 (59) primary loss = 0,
(64) HW output 1760 (cylinder) + (64a) shower 581. Cert 2474 HW kWh
3585 → 2408; SAP 64.66 → 70.35 (the residual to the lodged 78 is an
Unknown-meter data-fidelity artifact — the register recorded meter_type=3
"Unknown" but the lodged rating used an 18-hour off-peak meter, per RdSAP
§12 / the example worksheets).
Eval mean|err| 1.720 → 1.708 (headline 45.0%, flat ±1 cert — the
electric-flat segment is dominated by the meter data-fidelity artifact).
Regression green (2448 pass incl. golden 6035 + ASHP cohort 1e-4);
pyright net-zero.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
2bc73fb08d
commit
449d8c5b95
2 changed files with 45 additions and 0 deletions
|
|
@ -663,6 +663,11 @@ _INSTANTANEOUS_WATER_CODES: Final[frozenset[int]] = frozenset({907, 909})
|
|||
# zero-loss list, so primary loss is zero whenever this code is lodged.
|
||||
_WHC_ELECTRIC_IMMERSION: Final[int] = 903
|
||||
|
||||
# SAP 10.2 Table 4a "direct-acting electric boiler" (RdSAP 10 §12 p.62).
|
||||
# Named in the SAP 10.2 Table 3 (PDF p.160) primary-loss zero list, so a
|
||||
# 191 main feeding a cylinder incurs no primary circuit loss.
|
||||
_DIRECT_ACTING_ELECTRIC_BOILER_CODE: Final[int] = 191
|
||||
|
||||
# Water-heating codes for a dedicated "boiler/circulator for water
|
||||
# heating only" — SAP 10.2 Table 4a hot-water section (PDF p.166):
|
||||
# 911 gas, 912 liquid fuel, 913 solid fuel boiler/circulator; 921-931
|
||||
|
|
@ -5307,6 +5312,16 @@ def _primary_loss_applies(
|
|||
# kWh/yr — zero before this branch.
|
||||
if water_heating_code in _WATER_HEATING_BOILER_CIRCULATOR_CODES:
|
||||
return True
|
||||
# SAP 10.2 Table 3 (PDF p.160) zero-loss list names "Direct-acting
|
||||
# electric boiler" verbatim. RdSAP 10 §12 (p.62) classifies SAP code
|
||||
# 191 as the direct-acting electric boiler: its cylinder is immersion-
|
||||
# heated with no primary pipework, so no primary loss — even though it
|
||||
# lodges as main_heating_category 2 ("Boiler and radiators, electric")
|
||||
# and would otherwise hit the cat-{1,2} boiler branch below. Checked
|
||||
# before that branch so the electric-flat segment (cert 2474: WHC 901
|
||||
# + code 191 + cylinder) no longer accrues ~1177 kWh/yr phantom loss.
|
||||
if main.sap_main_heating_code == _DIRECT_ACTING_ELECTRIC_BOILER_CODE:
|
||||
return False
|
||||
if main.main_heating_category == 4:
|
||||
if hp_record is None:
|
||||
# No PCDB record → assume separate-vessel (conservative; the
|
||||
|
|
|
|||
|
|
@ -2164,6 +2164,36 @@ def test_secondary_electric_off_peak_bills_at_table_12a_direct_acting_high_rate(
|
|||
assert abs(secondary_rate_gbp_per_kwh - 0.1529) <= 1e-6
|
||||
|
||||
|
||||
def test_sap_table_3_primary_loss_zero_for_direct_acting_electric_boiler() -> None:
|
||||
# Arrange — SAP 10.2 Table 3 (PDF p.160) names "Direct-acting electric
|
||||
# boiler" verbatim in the primary-loss zero list (alongside electric
|
||||
# immersion, combi, CPSU, integral-vessel heat pump). RdSAP 10 §12
|
||||
# (p.62) classifies SAP code 191 as the "direct-acting electric
|
||||
# boiler", so a 191 main feeding a cylinder (WHC 901, "from main
|
||||
# system") incurs NO primary circuit loss — the DHW is immersion-
|
||||
# heated, with no primary pipework. The cat-{1,2} branch in
|
||||
# `_primary_loss_applies` mis-fires here (main_heating_category=2),
|
||||
# returning True and adding ~1177 kWh/yr of phantom primary loss to
|
||||
# the cat-2 electric-flat segment (cert 2474 worksheet (59) = 0).
|
||||
electric_boiler_main = MainHeatingDetail(
|
||||
has_fghrs=False,
|
||||
main_fuel_type=29, # electricity
|
||||
heat_emitter_type=1,
|
||||
emitter_temperature="NA",
|
||||
main_heating_control=2106,
|
||||
main_heating_category=2, # "Boiler and radiators, electric"
|
||||
sap_main_heating_code=191, # direct-acting electric boiler
|
||||
)
|
||||
|
||||
# Act — cylinder present, WHC 901 (HW from the electric boiler).
|
||||
applies = _primary_loss_applies(
|
||||
electric_boiler_main, True, None, water_heating_code=901,
|
||||
)
|
||||
|
||||
# Assert — direct-acting electric boiler → Table 3 zero list → no loss.
|
||||
assert applies is False
|
||||
|
||||
|
||||
def test_sap_table_3_primary_loss_applies_to_dedicated_water_heating_boiler_circulator() -> None:
|
||||
# Arrange — SAP 10.2 Table 3 (PDF p.160) row 1: primary circuit loss
|
||||
# applies when "hot water is heated by a heat generator (e.g. boiler)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue