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 b643bf0d..6b9daf5a 100644 --- a/tests/domain/sap10_calculator/rdsap/test_cert_to_inputs.py +++ b/tests/domain/sap10_calculator/rdsap/test_cert_to_inputs.py @@ -54,6 +54,7 @@ from domain.sap10_calculator.rdsap.cert_to_inputs import ( _apply_heat_network_hiu_default_store, # pyright: ignore[reportPrivateUsage] _cylinder_thermostat_present, # pyright: ignore[reportPrivateUsage] _has_suspended_timber_floor_per_spec, # pyright: ignore[reportPrivateUsage] + _heat_pump_apm_efficiencies, # pyright: ignore[reportPrivateUsage] _heat_network_code_302_effective_factor, # pyright: ignore[reportPrivateUsage] _heat_network_community_fuel_code, # pyright: ignore[reportPrivateUsage] _heat_network_distribution_electricity, # pyright: ignore[reportPrivateUsage] @@ -4841,6 +4842,57 @@ def test_hot_water_from_pcdb_heat_pump_bills_at_app_n_wh_high_rate() -> None: assert abs(rate_immersion - 0.0750) <= 1e-6 +def test_heat_pump_water_efficiency_is_floored_at_100pct_per_app_n3_7() -> None: + # Arrange — SAP 10.2 Appendix N3.7 ("Thermal efficiency for water + # heating – heat pumps", PDF p.109): "multiply the thermal efficiency + # (ηwater) for water heating by the in-use factor in Table N8; subject + # to a MINIMUM EFFICIENCY OF 100%." Our `_heat_pump_apm_efficiencies` + # applied the in-use factor but omitted the floor, so an oversized heat + # pump whose PSR-extended ηwater × 0.60 in-use fell below 100% billed + # water heating at that sub-100% efficiency (over-counting HW fuel). + # + # Accredited anchor: golden fixture case 56 (PCDB 100061, the config of + # cert 100110101713). At HLC 107.82 W/K the PSR is 3.107, above the + # record's largest PSR 2.0, so the Appendix N2 extension takes ηwater,3 + # from 198.9% toward 100% at 2 x 2.0 = 4.0 → 128.55%; × the 0.60 in-use + # factor (Open-EPC certs never lodge cylinder HX area → criteria fail) + # = 77.13% < 100% → the worksheet (216) reads 100.0000. In-range PSR + # (case 54, HLC large) keeps 0.60 × 198.9 = 119.34% (worksheet case 54 + # (216) = 112.5% for its 187.5% record — both above the floor, unchanged). + from domain.sap10_calculator.tables.pcdb import heat_pump_record + + record = heat_pump_record(100061) + assert record is not None + hp_main = MainHeatingDetail( + has_fghrs=False, + main_fuel_type=29, # electricity (heat pump) + heat_emitter_type=1, # radiators + emitter_temperature=0, + main_heating_control=2210, + main_heating_category=4, + sap_main_heating_code=None, + main_heating_index_number=100061, + ) + epc = _typical_semi_detached_epc() # no specified cylinder → in-use 0.60 + + # Act — oversized PSR (extension region) vs an in-range PSR. + _space_ext, water_ext = _heat_pump_apm_efficiencies( + main=hp_main, hp_record=record, + hlc_annual_avg_w_per_k=107.82, # PSR 3.107 > largest 2.0 + epc=epc, + ) or (None, None) + _space_in, water_in = _heat_pump_apm_efficiencies( + main=hp_main, hp_record=record, + hlc_annual_avg_w_per_k=400.0, # PSR 0.837, in range + epc=epc, + ) or (None, None) + + # Assert — extended HP water efficiency is floored at 100% (1.0); the + # in-range PSR keeps the un-floored 0.60 × 198.9% = 119.34%. + assert water_ext is not None and abs(water_ext - 1.0) < 1e-9 + assert water_in is not None and abs(water_in - 0.60 * 198.9 / 100.0) < 1e-9 + + def test_hot_water_immersion_off_peak_bills_at_table_13_blend() -> None: # Arrange — SAP 10.2 Table 12a (PDF p.191) "Immersion water heater" # row routes the WH column to Table 13 (PDF p.197). For an electric