mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-30 13:10:47 +00:00
fix(water): don't apply heat-pump water SCOP to a separate immersion (SAP N3.7a)
When a heat-pump cert lodges a PCDB Table 362 record, the APM override set BOTH the space efficiency (N3.6) and the water efficiency (N3.7a) from the heat pump unconditionally. But the PCDB η_water applies only when the DHW is heated BY the heat pump (water-heating code "from main": 901/902/914). A separate electric immersion (WHC 903) heats the water at 100% regardless of the space system, so applying the HP's water SCOP (187.5% × 0.6 in-use = 112.5%) under-counted the immersion's hot-water fuel. Gate the η_water override on the DHW-from-main codes; a separate immersion keeps its own 100% efficiency. Space η_space still always uses the APM value (the heat pump is the space main). Worksheet-validated to 1e-4 on simulated case 45 (HP space + WHC-903 immersion): water fuel (62) 1893.57 -> 2130.2639, total cost (255) 619.7433, CO2 692.13 — all matching the P960 exactly; SAP 60.53 -> rounds to the worksheet's 61. RdSAP-21.0.1 corpus unchanged (no HP+WHC903 certs in it). Pinned in test_cert_to_inputs (immersion fuel is main-independent). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9b0c590bf8
commit
72ef0f0e7b
2 changed files with 68 additions and 1 deletions
|
|
@ -7216,7 +7216,21 @@ def cert_to_inputs(
|
|||
epc=epc,
|
||||
)
|
||||
if apm_efficiencies is not None:
|
||||
eff, water_eff = apm_efficiencies
|
||||
# η_space (N3.6) always replaces the Table 4a default — the heat
|
||||
# pump is the space main. η_water (N3.7a) applies ONLY when the DHW
|
||||
# is actually heated by that main (WHC "from main": 901/902/914). A
|
||||
# separate electric immersion (WHC 903) or other independent DHW
|
||||
# source keeps its own water efficiency (immersion = 100%), not the
|
||||
# HP's water SCOP — otherwise a HP-space + immersion-DHW dwelling
|
||||
# under-counts its hot-water fuel (case 45: water 2130 -> 1894 kWh,
|
||||
# +1.5 SAP, because 187.5% × 0.6 in-use = 112.5% was applied where
|
||||
# the worksheet (216) uses 100%).
|
||||
eff, apm_water_eff = apm_efficiencies
|
||||
if (
|
||||
epc.sap_heating.water_heating_code
|
||||
in _WATER_INHERIT_FROM_MAIN_CODES
|
||||
):
|
||||
water_eff = apm_water_eff
|
||||
if (
|
||||
_is_heat_network_main(main)
|
||||
and epc.sap_heating.water_heating_code in _WATER_INHERIT_FROM_MAIN_CODES
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ from datatypes.epc.domain.epc_property_data import (
|
|||
from domain.sap10_ml.tests._fixtures import (
|
||||
make_building_part,
|
||||
make_floor_dimension,
|
||||
make_main_heating_detail,
|
||||
make_minimal_sap10_epc,
|
||||
make_sap_heating,
|
||||
make_window,
|
||||
|
|
@ -7581,3 +7582,55 @@ def test_index_less_mev_applies_table_4g_note_3_default_data_iuf() -> None:
|
|||
# 2.5x the raw-0.8 value, not the raw default.
|
||||
assert fan_kwh > 0.0
|
||||
assert abs(fan_kwh - expected) <= 1e-9
|
||||
|
||||
|
||||
def test_heat_pump_water_scop_not_applied_to_separate_immersion_dhw() -> None:
|
||||
# Arrange — SAP 10.2 Appendix N3.7(a): a heat pump's PCDB water
|
||||
# efficiency (η_water) applies to the DHW ONLY when the cylinder is
|
||||
# heated BY the heat pump. A separate electric immersion (WHC 903) heats
|
||||
# the water at 100% regardless of the space-heating system, so the HP's
|
||||
# water SCOP must NOT leak onto it. Invariant: a WHC-903 immersion's
|
||||
# hot-water fuel is INDEPENDENT of the main — a heat-pump main and a gas-
|
||||
# boiler main yield the SAME immersion fuel (both 100%, no primary loss).
|
||||
# Before the fix the APM override set η_water = 187.5% × 0.6 in-use =
|
||||
# 112.5% on the HP cert, under-counting its immersion fuel. Worksheet-
|
||||
# validated on simulated case 45: water (62) = 2130.26 kWh at η_water=100%,
|
||||
# not 2130.26 / 1.125 = 1893.57.
|
||||
hp_main = make_main_heating_detail(
|
||||
main_fuel_type=29, # electricity
|
||||
heat_emitter_type=1,
|
||||
main_heating_category=4, # heat pump
|
||||
main_heating_index_number=100053, # PCDB Table 362 ASHP (ECODAN 5 kW)
|
||||
main_heating_data_source=1,
|
||||
)
|
||||
boiler_main = make_main_heating_detail(
|
||||
main_fuel_type=26, # mains gas
|
||||
heat_emitter_type=1,
|
||||
main_heating_category=2, # gas boiler
|
||||
sap_main_heating_code=102,
|
||||
)
|
||||
|
||||
def _immersion_epc(main: MainHeatingDetail) -> EpcPropertyData:
|
||||
return make_minimal_sap10_epc(
|
||||
total_floor_area_m2=_TYPICAL_TFA_M2,
|
||||
habitable_rooms_count=4,
|
||||
country_code="ENG",
|
||||
has_hot_water_cylinder=True,
|
||||
sap_heating=make_sap_heating(
|
||||
main_heating_details=[main],
|
||||
water_heating_code=903, # separate electric immersion
|
||||
water_heating_fuel=30, # standard electricity
|
||||
cylinder_size=2,
|
||||
cylinder_insulation_type=1,
|
||||
cylinder_insulation_thickness_mm=25,
|
||||
),
|
||||
)
|
||||
|
||||
# Act
|
||||
hp_fuel = cert_to_inputs(_immersion_epc(hp_main)).hot_water_kwh_per_yr
|
||||
boiler_fuel = cert_to_inputs(_immersion_epc(boiler_main)).hot_water_kwh_per_yr
|
||||
|
||||
# Assert — the immersion DHW fuel is identical whether the space main is a
|
||||
# heat pump or a gas boiler (the HP water SCOP does not apply to it).
|
||||
assert hp_fuel > 0.0
|
||||
assert abs(hp_fuel - boiler_fuel) <= 1e-6
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue