mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-07-12 13:29:04 +00:00
recommend_secondary_heating_removal offers one standalone Option that clears the lodged secondary system. Eligibility is purely physical (offer iff sap_heating.secondary_heating_type is set) — no effectiveness gate, since a lodged secondary is a fixed emitter per RdSAP (portables are ignored), and the electric-storage §A.2.2 no-op is the Optimiser's call (ADR-0028 decisions 1-2). Priced at a flat per-dwelling decommission cost, not room-scaled. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
57 lines
2.6 KiB
Python
57 lines
2.6 KiB
Python
"""The Secondary Heating Removal Recommendation Generator (ADR-0028).
|
|
|
|
Offers to strip a dwelling's lodged secondary heating system so the main system
|
|
serves 100% of space heating. A **standalone, co-selectable** Recommendation —
|
|
not an Option in the Heating & Hot Water rec — because removing a secondary
|
|
heater is independent of (and combinable with) a tune-up or boiler upgrade.
|
|
|
|
Eligibility is purely physical: offered **iff a secondary is lodged**
|
|
(`sap_heating.secondary_heating_type` is set). RdSAP only records a secondary
|
|
when a *fixed* emitter is present (portable plug-in heaters are ignored), so a
|
|
lodged secondary is by definition a fixed unit worth removing. There is no
|
|
effectiveness gate — on an electric-storage main RdSAP §A.2.2 forces a default
|
|
secondary back, making removal a no-op, but that is the Optimiser's call (it
|
|
owns the economics), not eligibility's. Detection + pricing only; impact is
|
|
produced later by scoring (ADR-0016).
|
|
|
|
Priced at a flat per-dwelling decommission cost (one electrician visit to
|
|
disconnect a fixed/hard-wired heater + localised making-good), not scaled by
|
|
room count — the EPC lodges one secondary system with no heater count (ADR-0028).
|
|
"""
|
|
|
|
from typing import Final, Optional
|
|
|
|
from datatypes.epc.domain.epc_property_data import EpcPropertyData
|
|
from domain.modelling.measure_type import MeasureType
|
|
from domain.modelling.recommendation import Cost, MeasureOption, Recommendation
|
|
from domain.modelling.simulation import EpcSimulation, SecondaryHeatingOverlay
|
|
from repositories.product.product_repository import ProductRepository
|
|
|
|
_SECONDARY_HEATING_REMOVAL_MEASURE_TYPE: Final[MeasureType] = (
|
|
MeasureType.SECONDARY_HEATING_REMOVAL
|
|
)
|
|
|
|
|
|
def recommend_secondary_heating_removal(
|
|
epc: EpcPropertyData, products: ProductRepository
|
|
) -> Optional[Recommendation]:
|
|
"""Return a Secondary Heating Removal Recommendation — its single Option
|
|
clears the lodged secondary system — else None when no secondary is lodged
|
|
(nothing physical to remove)."""
|
|
if epc.sap_heating.secondary_heating_type is None:
|
|
return None
|
|
|
|
product = products.get(_SECONDARY_HEATING_REMOVAL_MEASURE_TYPE)
|
|
overlay = EpcSimulation(secondary_heating=SecondaryHeatingOverlay())
|
|
cost = Cost(
|
|
total=product.unit_cost_per_m2,
|
|
contingency_rate=product.contingency_rate,
|
|
)
|
|
option = MeasureOption(
|
|
measure_type=_SECONDARY_HEATING_REMOVAL_MEASURE_TYPE,
|
|
description="Remove the secondary heating system",
|
|
overlay=overlay,
|
|
cost=cost,
|
|
material_id=product.id,
|
|
)
|
|
return Recommendation(surface="Secondary Heating", options=(option,))
|