S0380.227: dedicated DHW-only system is not separately timed (Table 2b note b)

SAP 10.2 Table 2b note b (PDF p.159) applies the ×0.9 temperature-factor
reduction only when DHW is "separately timed" relative to space heating
on a SHARED heat generator ("boiler systems, warm air systems and heat
pump systems"). Per RdSAP 10 §10.5.1 (PDF p.55) a separate boiler/
circulator providing DHW only (water-heating code 911 = "Gas boiler/
circulator for water heating only") is NOT the main space-heating system
— so there is no shared timer to apply the ×0.9 against. `_separately_
timed_dhw` now returns False when water_heating_code is not "from main /
2nd-main system" ({901,902,914}), mirroring the existing WHC 903 electric-
immersion carve-out.

Simulated case 19 (electric storage main SAP 402 + WHS 911 + 210 L
loose-jacket cylinder) is the worksheet case. The single flag drives both:
- (53) Temperature factor: 0.54 → 0.6000 (worksheet base, no ×0.9)
- (55) storage loss/day: → 3.4531; (56)/(57)m Jan → 107.0456 (1e-4)
- (59)m primary loss: h=3 (43.31) → h=5 (Jan 64.5792), worksheet-exact

This also worksheet-pins S0380.224's loose-jacket storage loss magnitude
at 1e-4, previously only direction-validated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-06-04 17:44:11 +00:00
parent 796dce9d69
commit 5d4b55d7f9
2 changed files with 62 additions and 0 deletions

View file

@ -4764,6 +4764,20 @@ def _separately_timed_dhw(
return False
if main.sap_main_heating_code in _TABLE_4A_SOLID_FUEL_BOILER_CODES:
return False
# SAP 10.2 Table 2b note b + RdSAP 10 §10.5.1 (PDF p.55): the ×0.9
# reduction reflects DHW timed separately from space heating on a
# SHARED heat generator. When DHW is from a separate dedicated
# water-heating-only system (water-heating code not "from main /
# 2nd-main system" — e.g. 911 "Gas boiler/circulator for water
# heating only") there is no shared timer to apply the ×0.9 against,
# so the multiplier must not fire — the same principle as the WHC
# 903 electric-immersion carve-out above. Simulated case 19 (electric
# storage main + WHS 911 + 210 L loose-jacket cylinder) is the
# worksheet case: (53) Temperature factor 0.6000 (not 0.54) and
# (59)m primary loss h=5 (Jan 64.5792, not 43.31) both confirm the
# DHW is not separately timed.
if epc.sap_heating.water_heating_code not in _WATER_INHERIT_FROM_MAIN_CODES:
return False
return bool(epc.has_hot_water_cylinder)

View file

@ -1864,6 +1864,54 @@ def test_separately_timed_dhw_excludes_electric_immersion_per_table_2b_note_b()
assert sep_immersion is False
def test_separately_timed_dhw_excludes_dedicated_water_heater_per_table_2b_note_b() -> None:
# Arrange — SAP 10.2 Table 2b note b) (PDF p.159) applies the ×0.9
# temperature-factor reduction only when DHW "is separately timed"
# relative to space heating on a SHARED heat generator ("boiler
# systems, warm air systems and heat pump systems"). Per RdSAP 10
# §10.5.1 (PDF p.55) a separate boiler/circulator providing DHW only
# (water-heating code 911 = "Gas boiler/circulator for water heating
# only") is NOT the main space-heating system — here space is by
# electric storage heaters (SAP code 402). With no shared generator
# there is no separate DHW timer to apply the ×0.9 against, so the
# multiplier must not fire — the same principle as the WHC 903
# electric-immersion carve-out above. Simulated case 19's worksheet
# confirms it: cylinder thermostat present + "Separate Time Control:
# No" → (53) Temperature factor 0.6000 (base, not 0.54 = 0.6 × 0.9)
# AND (59)m primary loss h=5 (winter Jan 64.5792), not h=3 (43.31).
storage_heater_main = MainHeatingDetail(
has_fghrs=False,
main_fuel_type=30, # electricity
heat_emitter_type="",
emitter_temperature=1,
main_heating_control=2402, # storage-heater auto-charge control
main_heating_category=None,
sap_main_heating_code=402, # electric storage heaters
)
dedicated_gas_water_heater_epc = 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=[storage_heater_main],
water_heating_fuel=26, # mains gas (dedicated WHS boiler)
water_heating_code=911, # gas boiler/circulator, water only
cylinder_size=4,
cylinder_insulation_type=2, # loose jacket
cylinder_insulation_thickness_mm=50,
),
)
# Act
separately_timed = _separately_timed_dhw(
dedicated_gas_water_heater_epc, storage_heater_main,
)
# Assert — dedicated water-heating-only system → not separately timed.
assert separately_timed is False
def test_water_efficiency_uses_table_4a_water_column_for_heat_pumps_per_sap_10_2() -> None:
# Arrange — SAP 10.2 Table 4a (PDF p.163-164) gives heat pumps two
# efficiency columns: "space" and "water". For low-temperature