Model/tests/orchestration/test_modelling_heat_pump_sizing_threading.py
Khalim Conn-Kowlessar cb91954bb4 The orchestrator threads the dwelling design heat loss into ASHP sizing 🟥
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 10:31:57 +00:00

60 lines
2.2 KiB
Python

"""The ModellingOrchestrator threads the dwelling's SAP design heat loss into
the heating Recommendation Generator so the ASHP is sized to the dwelling
(ADR-0049), mirroring how planning_restrictions and the solar potential are
threaded. Tests the candidate-wiring seam directly; the end-to-end run-through-
repos path is covered by the DB integration tests.
"""
from datatypes.epc.domain.epc_property_data import EpcPropertyData
from domain.geospatial.planning_restrictions import PlanningRestrictions
from domain.modelling.measure_type import MeasureType
from domain.modelling.product import Product
from domain.modelling.recommendation import Recommendation
from orchestration.modelling_orchestrator import (
_candidate_recommendations, # pyright: ignore[reportPrivateUsage]
)
from repositories.product.product_repository import ProductRepository
from tests.domain.modelling._elmhurst_recommendation import (
parse_recommendation_summary,
)
class _StubProducts(ProductRepository):
def get(self, measure_type: str) -> Product:
return Product(
measure_type=measure_type,
unit_cost_per_m2=0.0,
contingency_rate=0.15,
id=909,
)
def _ashp_eligible_house() -> EpcPropertyData:
epc = parse_recommendation_summary(
"ashp_from_system_boiler_with_cylinder_001431_before.pdf"
)
epc.property_type = "House"
return epc
def test_candidate_recommendations_sizes_the_ashp_to_the_threaded_design_heat_loss() -> (
None
):
# Arrange — an ASHP-eligible house and a high (17.5 kW) design heat loss.
epc = _ashp_eligible_house()
# Act
recommendations: list[Recommendation] = _candidate_recommendations(
epc, _StubProducts(), PlanningRestrictions(), None, None, design_heat_loss_kw=17.5
)
# Assert — the ASHP is sized to the load (capped 12 kW aroTHERM plus 110281),
# not the fixed 5 kW / floor-area-proxy unit.
heating = next(r for r in recommendations if r.surface == "Heating & Hot Water")
ashp = next(
o
for o in heating.options
if o.measure_type == MeasureType.AIR_SOURCE_HEAT_PUMP
)
assert ashp.overlay.heating is not None
assert ashp.overlay.heating.main_heating_index_number == 110281