mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
EpcSimulation is the Simulation Overlay — a narrow all-optional partial mirror of EpcPropertyData/SapBuildingPart (wall surface first), targeting building parts by BuildingPartIdentifier (composition, not inheritance). apply_simulations(baseline, simulations) deep-copies the baseline, folds overlays in order (later wins on a shared field) via a generic non-None field write, and returns a throwaway EpcPropertyData for the calculator; the baseline is never mutated. Four behaviour tests (hand-built EPD from the 000490 fixture, no PDF): targeted-write-leaves-others-untouched, empty-overlay no-op, sequential last-wins, baseline-immutability. pyright strict clean. Slice 1 of the Modelling stage rebuild (ADR-0016). Closes #1153. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
34 lines
1.4 KiB
Python
34 lines
1.4 KiB
Python
"""The Overlay Applicator — folds an ordered set of Simulation Overlays onto
|
|
a baseline EpcPropertyData and returns a new one for the calculator.
|
|
|
|
Sequential fold: overlays are applied in order and a later overlay wins on a
|
|
field it shares with an earlier one. The baseline is never mutated; the
|
|
returned EpcPropertyData is throwaway (handed to the calculator for scoring,
|
|
then discarded). See ADR-0016.
|
|
"""
|
|
|
|
import copy
|
|
from dataclasses import fields
|
|
from typing import Sequence
|
|
|
|
from datatypes.epc.domain.epc_property_data import EpcPropertyData
|
|
from domain.modelling.simulation import EpcSimulation
|
|
|
|
|
|
def apply_simulations(
|
|
baseline: EpcPropertyData, simulations: Sequence[EpcSimulation]
|
|
) -> EpcPropertyData:
|
|
"""Return a copy of ``baseline`` with every Simulation Overlay's non-``None``
|
|
fields written onto the building part it targets, applied in order."""
|
|
result: EpcPropertyData = copy.deepcopy(baseline)
|
|
parts_by_id = {part.identifier: part for part in result.sap_building_parts}
|
|
|
|
for simulation in simulations:
|
|
for identifier, overlay in simulation.building_parts.items():
|
|
part = parts_by_id[identifier]
|
|
for overlay_field in fields(overlay):
|
|
value = getattr(overlay, overlay_field.name)
|
|
if value is not None:
|
|
setattr(part, overlay_field.name, value)
|
|
|
|
return result
|