mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-30 13:10:47 +00:00
test(modelling): ASHP before/after cascade pin (001431) at 1e-4
A typical mains-gas combi house re-lodged as an air-source heat pump closes at 1e-4 (gas-boiler 1 example from the technical specialist). Closes one named gap the pin surfaced: a whole-system replacement to a PCDB-indexed system left the old Table 4a sap_main_heating_code (104) beside the new heat-pump index, and the stale code won the calculator's efficiency dispatch (hot water billed at boiler not HP efficiency, ΔSAP 3.98). _fold_heating now enforces the mutual exclusion of the two efficiency anchors (setting an index clears the SAP code and vice versa). Also fixed a pre-existing pyright annotation in the lighting applicator test. ADR-0024. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
a9da21c4b6
commit
a1fc697d93
5 changed files with 75 additions and 1 deletions
|
|
@ -90,6 +90,16 @@ def _fold_heating(epc: EpcPropertyData, overlay: HeatingOverlay) -> None:
|
|||
value = getattr(overlay, field_name)
|
||||
if value is not None:
|
||||
setattr(main, field_name, value)
|
||||
# `main_heating_index_number` (PCDB-resolved, e.g. a heat pump) and
|
||||
# `sap_main_heating_code` (Table 4a-resolved, e.g. storage heaters) are
|
||||
# mutually-exclusive efficiency anchors: a whole-system replacement to one
|
||||
# must clear the other, else a stale code from the old system wins the
|
||||
# calculator's dispatch (e.g. a gas-boiler code 104 left beside a heat-pump
|
||||
# index makes hot water use boiler efficiency, not the HP SCOP).
|
||||
if overlay.main_heating_index_number is not None:
|
||||
main.sap_main_heating_code = None
|
||||
elif overlay.sap_main_heating_code is not None:
|
||||
main.main_heating_index_number = None
|
||||
for field_name in _SAP_HEATING_FIELDS:
|
||||
value = getattr(overlay, field_name)
|
||||
if value is not None:
|
||||
|
|
|
|||
BIN
tests/domain/modelling/fixtures/ashp_001431_after.pdf
Normal file
BIN
tests/domain/modelling/fixtures/ashp_001431_after.pdf
Normal file
Binary file not shown.
Binary file not shown.
|
|
@ -620,3 +620,24 @@ def test_hhr_storage_overlay_reproduces_the_relodged_after_from_no_system() -> N
|
|||
|
||||
# Act / Assert
|
||||
_assert_overlay_reproduces_after(before, after, option.overlay)
|
||||
|
||||
|
||||
def test_ashp_overlay_reproduces_the_relodged_after_from_a_gas_boiler() -> None:
|
||||
# Arrange — a typical mains-gas combi house re-lodged as an air-source heat
|
||||
# pump (fuel 26 -> 30, SAP code 104 -> PCDB index 101413 + category 4,
|
||||
# control 2106 -> 2210), off mains gas, gaining a heat-pump cylinder
|
||||
# (ADR-0024).
|
||||
before: EpcPropertyData = parse_recommendation_summary(
|
||||
"ashp_from_gas_boiler_001431_before.pdf"
|
||||
)
|
||||
after: EpcPropertyData = parse_recommendation_summary(
|
||||
"ashp_001431_after.pdf"
|
||||
)
|
||||
recommendation: Recommendation | None = recommend_heating(before, _AnyProduct())
|
||||
assert recommendation is not None
|
||||
option = next(
|
||||
o for o in recommendation.options if o.measure_type == "air_source_heat_pump"
|
||||
)
|
||||
|
||||
# Act / Assert
|
||||
_assert_overlay_reproduces_after(before, after, option.overlay)
|
||||
|
|
|
|||
|
|
@ -327,11 +327,54 @@ def test_baseline_heating_is_not_mutated_by_a_heating_overlay() -> None:
|
|||
assert baseline.sap_energy_source.mains_gas == original_mains_gas
|
||||
|
||||
|
||||
def test_heating_index_overlay_clears_a_stale_sap_main_heating_code() -> None:
|
||||
# Arrange — 000490's gas combi lodges a Table 4a code; an ASHP bundle sets a
|
||||
# PCDB index instead. The two are mutually-exclusive efficiency anchors, so
|
||||
# the stale code must be cleared or it wins the calculator's dispatch.
|
||||
baseline: EpcPropertyData = build_epc()
|
||||
baseline.sap_heating.main_heating_details[0].sap_main_heating_code = 104
|
||||
|
||||
# Act
|
||||
result: EpcPropertyData = apply_simulations(
|
||||
baseline,
|
||||
[
|
||||
EpcSimulation(
|
||||
heating=HeatingOverlay(
|
||||
main_heating_index_number=101413, main_heating_category=4
|
||||
)
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
# Assert — the index is set and the old SAP code is gone.
|
||||
main = result.sap_heating.main_heating_details[0]
|
||||
assert main.main_heating_index_number == 101413
|
||||
assert main.sap_main_heating_code is None
|
||||
|
||||
|
||||
def test_heating_sap_code_overlay_clears_a_stale_index() -> None:
|
||||
# Arrange — a dwelling with a PCDB-indexed system; an HHR storage bundle sets
|
||||
# a Table 4a code instead, so the stale index must be cleared.
|
||||
baseline: EpcPropertyData = build_epc()
|
||||
baseline.sap_heating.main_heating_details[0].main_heating_index_number = 8262
|
||||
|
||||
# Act
|
||||
result: EpcPropertyData = apply_simulations(
|
||||
baseline,
|
||||
[EpcSimulation(heating=HeatingOverlay(sap_main_heating_code=409))],
|
||||
)
|
||||
|
||||
# Assert
|
||||
main = result.sap_heating.main_heating_details[0]
|
||||
assert main.sap_main_heating_code == 409
|
||||
assert main.main_heating_index_number is None
|
||||
|
||||
|
||||
def test_baseline_lighting_is_not_mutated_by_a_lighting_overlay() -> None:
|
||||
# Arrange — 000490 lodges 8 low-energy-unknown bulbs, 0 LED.
|
||||
baseline: EpcPropertyData = build_epc()
|
||||
original_led: int = baseline.led_fixed_lighting_bulbs_count
|
||||
original_lel: int = baseline.low_energy_fixed_lighting_bulbs_count
|
||||
original_lel: int | None = baseline.low_energy_fixed_lighting_bulbs_count
|
||||
|
||||
# Act — fold an all-LED overlay (led = the 8 total).
|
||||
_: EpcPropertyData = apply_simulations(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue