mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
S0380.230: electric room heaters (cat 10) on off-peak bill at Table 12a direct-acting high rate
SAP 10.2 Table 12a Grid 1 (PDF p.191): an electric room heater (RdSAP main_heating_category 10, e.g. SAP code 691) is direct-acting electric, so it sits on the "Other systems including direct-acting electric" row — 7-hour high-rate fraction 1.00, 10-hour 0.50. It runs on demand, mostly at the HIGH rate; it does NOT earn the 100%-low-rate of overnight storage charging (which is category 7). `_table_12a_system_for_main` only mapped ASHP, so an electric room heater fell through to the "100% low-rate" fallback (5.50 p, £0.0550), under- charging space heating by ~9.79 p/kWh and systematically OVER-rating the cluster. Now maps electric cat-10 mains to OTHER_DIRECT_ACTING_ELECTRIC (gated on `_is_electric_main`, so gas/solid-fuel cat-10 room heaters are excluded). The same Table 12a fraction flows through cost, CO2 (Table 12d) and PE (Table 12e) — all three callers already pre-gate on electric. Mirror of S0380.228 (same fallback bug for electric SECONDARY heating). 1,000-cert 2026 API sample (no worksheet for this cluster — ±0.5-vs-lodged fallback bar): cat-10 mean |err| 9.49 → 7.11, %<0.5 10.4% → 16.7%; headline %<0.5 42.5% → 42.9%, overall mean |err| 2.29 → 2.16. cat-7 (storage) and cat-2 (gas) unchanged. Full §4 suite green (2405 passed). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
86a725224b
commit
0476b4b235
2 changed files with 59 additions and 0 deletions
|
|
@ -2138,6 +2138,16 @@ def _table_12a_system_for_main(
|
|||
main.main_heating_index_number is not None
|
||||
and heat_pump_record(main.main_heating_index_number) is not None
|
||||
)
|
||||
# Electric room heaters (RdSAP main_heating_category 10) are direct-
|
||||
# acting electric → SAP 10.2 Table 12a Grid 1 (PDF p.191) "Other
|
||||
# systems including direct-acting electric" row (7-hour high-rate
|
||||
# fraction 1.00, 10-hour 0.50). Distinct from electric STORAGE
|
||||
# heaters (category 7), which charge off-peak and correctly fall
|
||||
# through to None here (→ 100% low rate). Gated on `_is_electric_main`
|
||||
# so a non-electric room heater (gas / solid-fuel cat 10) is excluded;
|
||||
# all callers already pre-gate on electric, this is belt-and-braces.
|
||||
if main.main_heating_category == 10 and _is_electric_main(main):
|
||||
return Table12aSystem.OTHER_DIRECT_ACTING_ELECTRIC
|
||||
# ASHP — Table 4a rows 211-217 (earlier generations) + 221-227
|
||||
# (2013+) cover the air-source space. Warm-air ASHPs are 521-524.
|
||||
if code is not None and (
|
||||
|
|
|
|||
|
|
@ -2938,6 +2938,55 @@ def test_space_heating_off_peak_fallback_uses_actual_tariff_low_rate_not_e7() ->
|
|||
assert abs(cost_eighteen_hour - 0.0741) <= 1e-6
|
||||
|
||||
|
||||
def test_space_heating_electric_room_heater_off_peak_bills_at_direct_acting_high_rate() -> None:
|
||||
# Arrange — an ELECTRIC room heater (RdSAP main_heating_category 10,
|
||||
# e.g. SAP code 691) is direct-acting electric, so SAP 10.2 Table 12a
|
||||
# Grid 1 (PDF p.191) puts it on the "Other systems including direct-
|
||||
# acting electric" row: 7-hour high-rate fraction 1.00, 10-hour 0.50.
|
||||
# Unlike STORAGE heaters (category 7), which charge off-peak and so
|
||||
# correctly bill 100% at the low rate, a room heater runs on demand —
|
||||
# mostly at the HIGH rate. `_table_12a_system_for_main` only mapped
|
||||
# ASHP, so a room heater fell through to the "100% low-rate" fallback
|
||||
# (5.50 p, £0.0550), under-charging space heating by ~9.79 p/kWh and
|
||||
# systematically OVER-rating the cat-10 cluster (1,000-cert API sample:
|
||||
# 48 certs, mean |err| 9.49, signed +5.08). The fix maps electric
|
||||
# cat-10 mains to OTHER_DIRECT_ACTING_ELECTRIC. Mirror of S0380.228
|
||||
# (which fixed the same fallback for electric SECONDARY heating).
|
||||
from domain.sap10_calculator.tables.table_12a import Tariff
|
||||
electric_room_heater_main = MainHeatingDetail(
|
||||
has_fghrs=False,
|
||||
main_fuel_type=30, # standard electricity
|
||||
heat_emitter_type=2,
|
||||
emitter_temperature=1,
|
||||
main_heating_control=2602,
|
||||
main_heating_category=10, # electric room heaters
|
||||
sap_main_heating_code=691,
|
||||
)
|
||||
gas_room_heater_main = MainHeatingDetail(
|
||||
has_fghrs=False,
|
||||
main_fuel_type=1, # mains gas — NOT electric
|
||||
heat_emitter_type=2,
|
||||
emitter_temperature=1,
|
||||
main_heating_control=2602,
|
||||
main_heating_category=10, # gas room heater (also cat 10)
|
||||
sap_main_heating_code=631,
|
||||
)
|
||||
|
||||
# Act — 7-hour off-peak tariff.
|
||||
electric_rate = _space_heating_fuel_cost_gbp_per_kwh(
|
||||
electric_room_heater_main, Tariff.SEVEN_HOUR, prices=SAP_10_2_SPEC_PRICES,
|
||||
)
|
||||
gas_rate = _space_heating_fuel_cost_gbp_per_kwh(
|
||||
gas_room_heater_main, Tariff.SEVEN_HOUR, prices=SAP_10_2_SPEC_PRICES,
|
||||
)
|
||||
|
||||
# Assert — electric room heater: 1.00 × 15.29 p = £0.1529 (high rate).
|
||||
# Gas room heater is unaffected (non-electric → single Table 32 rate,
|
||||
# not the off-peak electric split).
|
||||
assert abs(electric_rate - 0.1529) <= 1e-6
|
||||
assert abs(gas_rate - 0.0550) > 1e-6
|
||||
|
||||
|
||||
def test_heat_network_dlf_full_table_12c_age_band_coverage() -> None:
|
||||
# Arrange — SAP 10.2 Table 12c (page 193) heat-network Distribution
|
||||
# Loss Factor by dwelling age band A..M. None → K-or-newer
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue