From 7e355ce2ea2b2325995dac1fe330d6cecc920fc1 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Wed, 15 Jul 2026 10:29:42 +0000 Subject: [PATCH] =?UTF-8?q?Treat=20water-only=20heat-network=20primary=20p?= =?UTF-8?q?ipework=20as=20insulated=20=F0=9F=9F=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SAP 10.2 Table 3 ("For heat networks apply the formula above with p = 1.0 and h = 3 for all months") and §4.3's "insulated pipework" literal both scope on the DHW source, so a water-only network gets the same row as a network space main. Was falling back to the RdSAP §3 age-band default — band E → p=0, h=5 — billing 64.58 kWh in January against the spec's 23.26. Co-Authored-By: Claude Opus 4.8 (1M context) --- domain/sap10_calculator/rdsap/cert_to_inputs.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/domain/sap10_calculator/rdsap/cert_to_inputs.py b/domain/sap10_calculator/rdsap/cert_to_inputs.py index 21b05af9b..a1a8af635 100644 --- a/domain/sap10_calculator/rdsap/cert_to_inputs.py +++ b/domain/sap10_calculator/rdsap/cert_to_inputs.py @@ -7108,13 +7108,21 @@ def _primary_loss_override( water_heating_code=epc.sap_heating.water_heating_code, ): return None + # Heat-network DHW: either the space main is a network (WHC 901/902/914 + # inherit its DHW) or the DHW is its own water-only community scheme + # (WHC 950/951/952). SAP 10.2 §4.3 (PDF p.24) and Table 3's heat-network + # row both scope on the DHW source — "Where hot water is provided by a + # heat network" — not on the space main. + heat_network_dhw = is_heat_network_main(main) or ( + epc.sap_heating.water_heating_code in _WATER_HEAT_NETWORK_ONLY_CODES + ) # SAP 10.2 §4 "Heat networks" (PDF p.17 line 1482) pins community- # heating primary pipework to "insulated" (p=1.0), overriding the # RdSAP §3 age-band default which would otherwise return 0 for # pre-2007 stock. See `_HEAT_NETWORK_PIPEWORK_INSULATION_FRACTION`. pipework_p = ( _HEAT_NETWORK_PIPEWORK_INSULATION_FRACTION - if is_heat_network_main(main) + if heat_network_dhw else _pipework_insulation_fraction_table_3(primary_age) ) base = primary_loss_monthly_kwh( @@ -7126,7 +7134,7 @@ def _primary_loss_override( # row applies regardless of the thermostat / separate-timing # lodgement (and so is robust to the community-fuel-as-electric # collision that would otherwise route DHW to the h=5 row). - heat_network=is_heat_network_main(main), + heat_network=heat_network_dhw, ) # SAP 10.2 §12.4.4 (PDF p.36-37): for back-boiler combos summer DHW # comes from an electric immersion, not from the boiler — the boiler