"""The Simulation Overlay (`EpcSimulation`) — the change a single Measure Option makes to a Property's EpcPropertyData. An all-optional partial mirror of EpcPropertyData / SapBuildingPart, covering the retrofit-relevant surface only (wall fields first). It is *not* an EpcPropertyData — composition, not inheritance — and carries no scores. Building parts are targeted by `BuildingPartIdentifier` so a measure addresses the exact `SapBuildingPart` (the main wall vs an extension). See CONTEXT.md. """ from dataclasses import dataclass, field from typing import Mapping, Optional from datatypes.epc.domain.epc_property_data import BuildingPartIdentifier @dataclass(frozen=True) class BuildingPartOverlay: """All-optional partial of `SapBuildingPart` (wall surface first). A `None` field means "leave the baseline value unchanged". """ wall_insulation_type: Optional[int] = None roof_insulation_thickness: Optional[int] = None floor_insulation_thickness: Optional[int] = None floor_insulation_type_str: Optional[str] = None @dataclass(frozen=True) class VentilationOverlay: """All-optional partial of `SapVentilation` — the whole-dwelling ventilation change a Measure Option makes (e.g. retrofit MEV). Unlike a `BuildingPartOverlay` this targets no building part; it folds onto the dwelling's single `sap_ventilation`. `mechanical_ventilation_kind` names the SAP10.2 §2 mechanical-ventilation kind (the `MechanicalVentilationKind` enum name, e.g. ``"EXTRACT_OR_PIV_OUTSIDE"`` for decentralised MEV). A `None` field means "leave the baseline value unchanged". """ mechanical_ventilation_kind: Optional[str] = None def _no_building_parts() -> dict[BuildingPartIdentifier, BuildingPartOverlay]: return {} @dataclass(frozen=True) class EpcSimulation: """A Simulation Overlay: the per-building-part changes a Measure Option makes, keyed by `BuildingPartIdentifier`, plus an optional whole-dwelling `ventilation` change (the Measure Dependency surface — ADR-0016).""" building_parts: Mapping[BuildingPartIdentifier, BuildingPartOverlay] = field( default_factory=_no_building_parts ) ventilation: Optional[VentilationOverlay] = None