mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-07-12 13:29:04 +00:00
119 lines
4.1 KiB
Python
119 lines
4.1 KiB
Python
"""Behaviour of the floor Recommendation Generator: detecting an uninsulated
|
|
ground floor and its construction (suspended vs solid), emitting the matching
|
|
single insulation Option with overlay + priced Cost. A floor is one
|
|
construction, so this is a single-Option Recommendation (like cavity walls).
|
|
"""
|
|
|
|
from datatypes.epc.domain.epc_property_data import (
|
|
BuildingPartIdentifier,
|
|
EpcPropertyData,
|
|
SapBuildingPart,
|
|
)
|
|
from domain.modelling.scoring.overlay_applicator import apply_simulations
|
|
from domain.modelling.product import Product
|
|
from domain.modelling.recommendation import Recommendation
|
|
from domain.modelling.generators.floor_recommendation import recommend_floor_insulation
|
|
from repositories.product.product_repository import ProductRepository
|
|
from tests.domain.sap10_calculator.worksheet._elmhurst_worksheet_000490 import (
|
|
build_epc,
|
|
)
|
|
|
|
|
|
class _StubProducts(ProductRepository):
|
|
def get(self, measure_type: str) -> Product:
|
|
return Product(
|
|
measure_type=measure_type, unit_cost_per_m2=25.0, contingency_rate=0.20
|
|
)
|
|
|
|
|
|
def _main(epc: EpcPropertyData) -> SapBuildingPart:
|
|
return next(
|
|
p for p in epc.sap_building_parts if p.identifier is BuildingPartIdentifier.MAIN
|
|
)
|
|
|
|
|
|
def test_uninsulated_suspended_floor_yields_suspended_insulation() -> None:
|
|
# Arrange — 000490 MAIN: "Suspended timber", "As built" (uninsulated)
|
|
baseline: EpcPropertyData = build_epc()
|
|
|
|
# Act
|
|
recommendation: Recommendation | None = recommend_floor_insulation(
|
|
baseline, _StubProducts()
|
|
)
|
|
|
|
# Assert
|
|
assert recommendation is not None
|
|
assert recommendation.surface == "Ground floor"
|
|
assert len(recommendation.options) == 1
|
|
option = recommendation.options[0]
|
|
assert option.measure_type == "suspended_floor_insulation"
|
|
simulated: EpcPropertyData = apply_simulations(baseline, [option.overlay])
|
|
assert _main(simulated).floor_insulation_thickness == 100
|
|
|
|
|
|
def test_uninsulated_solid_floor_yields_solid_insulation() -> None:
|
|
# Arrange
|
|
baseline: EpcPropertyData = build_epc()
|
|
_main(baseline).floor_construction_type = "Solid"
|
|
|
|
# Act
|
|
recommendation: Recommendation | None = recommend_floor_insulation(
|
|
baseline, _StubProducts()
|
|
)
|
|
|
|
# Assert
|
|
assert recommendation is not None
|
|
assert recommendation.options[0].measure_type == "solid_floor_insulation"
|
|
|
|
|
|
def test_at_regs_age_band_floor_yields_no_recommendation() -> None:
|
|
# Arrange — a solid ground floor lodged as-built at construction age band
|
|
# L (2012-2022). RdSAP's BS EN ISO 13370 cascade assigns it the at-regs
|
|
# U-value and 100 mm of added insulation resolves to the same (or a
|
|
# no-better) value — the measure cannot change the modelled floor, so
|
|
# offering it sells £3-4k of insulation for +0.00 SAP (portfolio 796:
|
|
# properties 709782/709790). The Floor U-Value Gate withholds it — the
|
|
# floor arm of ADR-0051's deferred follow-up.
|
|
baseline: EpcPropertyData = build_epc()
|
|
main: SapBuildingPart = _main(baseline)
|
|
main.floor_construction_type = "Solid"
|
|
main.construction_age_band = "L"
|
|
|
|
# Act
|
|
recommendation: Recommendation | None = recommend_floor_insulation(
|
|
baseline, _StubProducts()
|
|
)
|
|
|
|
# Assert
|
|
assert recommendation is None
|
|
|
|
|
|
def test_already_insulated_floor_yields_no_recommendation() -> None:
|
|
# Arrange
|
|
baseline: EpcPropertyData = build_epc()
|
|
_main(baseline).floor_insulation_thickness = "100"
|
|
|
|
# Act
|
|
recommendation: Recommendation | None = recommend_floor_insulation(
|
|
baseline, _StubProducts()
|
|
)
|
|
|
|
# Assert
|
|
assert recommendation is None
|
|
|
|
|
|
def test_floor_option_carries_cost_from_ground_floor_area_and_product() -> None:
|
|
# Arrange — 000490 MAIN ground floor area 14.85 m^2
|
|
baseline: EpcPropertyData = build_epc()
|
|
|
|
# Act
|
|
recommendation: Recommendation | None = recommend_floor_insulation(
|
|
baseline, _StubProducts()
|
|
)
|
|
|
|
# Assert
|
|
assert recommendation is not None
|
|
cost = recommendation.options[0].cost
|
|
assert cost is not None
|
|
assert abs(cost.total - 14.85 * 25.0) <= 0.01
|
|
assert abs(cost.contingency_rate - 0.20) <= 1e-9
|