"""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 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`.""" building_parts: Mapping[BuildingPartIdentifier, BuildingPartOverlay] = field( default_factory=_no_building_parts )