diff --git a/domain/sap10_calculator/rdsap/cert_to_inputs.py b/domain/sap10_calculator/rdsap/cert_to_inputs.py index 21619ed4..417a9e28 100644 --- a/domain/sap10_calculator/rdsap/cert_to_inputs.py +++ b/domain/sap10_calculator/rdsap/cert_to_inputs.py @@ -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) diff --git a/tests/domain/sap10_calculator/rdsap/test_cert_to_inputs.py b/tests/domain/sap10_calculator/rdsap/test_cert_to_inputs.py index 3be0ea4f..c0e8df0a 100644 --- a/tests/domain/sap10_calculator/rdsap/test_cert_to_inputs.py +++ b/tests/domain/sap10_calculator/rdsap/test_cert_to_inputs.py @@ -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