mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
recommend_floor_insulation(epc, products) detects an uninsulated ground floor (SapBuildingPart.floor_insulation_thickness blank/zero) and its construction from floor_construction_type — 'Suspended timber' -> suspended_floor_insulation, 'Solid' -> solid_floor_insulation — emitting the matching single Option (a floor is one construction, like a cavity wall) with the overlay (floor_insulation_thickness = 100 mm) and a priced Cost (ground-floor area x the Product's fully-loaded unit cost + contingency). - building_geometry.ground_floor_area(epc, identifier): the lowest floor's (floor == 0) area. Pinned 14.85 m^2 on 000490 MAIN. - BuildingPartOverlay gains floor_insulation_thickness (generic Applicator writes it unchanged). suspended (0.20) / solid (0.26) floor contingencies. Progress on #1159 (generator + geometry); end-to-end + Elmhurst pin pending the orchestrator (#1157) and parser. Four behaviour tests (suspended / solid / none / cost) + geometry pin. pyright strict clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
24 lines
847 B
Python
24 lines
847 B
Python
"""Per-Measure-Type contingency rates.
|
|
|
|
The one cost component carried separately from a Product's fully-loaded total
|
|
(CONTEXT.md). Mirrors the legacy `recommendations/Costs.py::Costs.CONTINGENCIES`;
|
|
extended as each measure type lands.
|
|
"""
|
|
|
|
_CONTINGENCY_RATES: dict[str, float] = {
|
|
"cavity_wall_insulation": 0.10,
|
|
"loft_insulation": 0.10,
|
|
"suspended_floor_insulation": 0.20,
|
|
"solid_floor_insulation": 0.26,
|
|
}
|
|
|
|
|
|
def contingency_rate(measure_type: str) -> float:
|
|
"""Return the contingency rate for a Measure Type, raising if unknown
|
|
(strict — do not silently default, per the repo's strict-raise convention)."""
|
|
try:
|
|
return _CONTINGENCY_RATES[measure_type]
|
|
except KeyError as exc:
|
|
raise ValueError(
|
|
f"no contingency rate configured for measure type {measure_type!r}"
|
|
) from exc
|