mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-07-12 13:29:04 +00:00
Prefer a MAIN-bearing prediction template so EPC-less dwellings predict 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
fc7cfc70e8
commit
abb822c1c7
1 changed files with 28 additions and 0 deletions
|
|
@ -9,6 +9,7 @@ from datetime import date
|
||||||
from typing import Optional, Union
|
from typing import Optional, Union
|
||||||
|
|
||||||
from datatypes.epc.domain.epc_property_data import (
|
from datatypes.epc.domain.epc_property_data import (
|
||||||
|
BuildingPartIdentifier,
|
||||||
EpcPropertyData,
|
EpcPropertyData,
|
||||||
MainHeatingDetail,
|
MainHeatingDetail,
|
||||||
SapBuildingPart,
|
SapBuildingPart,
|
||||||
|
|
@ -32,6 +33,7 @@ from domain.epc_prediction.prediction_target import PredictionTarget
|
||||||
def _epc(
|
def _epc(
|
||||||
*,
|
*,
|
||||||
building_parts: int = 1,
|
building_parts: int = 1,
|
||||||
|
identifier: BuildingPartIdentifier = BuildingPartIdentifier.MAIN,
|
||||||
floor_area: float = 80.0,
|
floor_area: float = 80.0,
|
||||||
wall_construction: Union[int, str] = 1,
|
wall_construction: Union[int, str] = 1,
|
||||||
wall_insulation_type: Union[int, str] = 1,
|
wall_insulation_type: Union[int, str] = 1,
|
||||||
|
|
@ -57,6 +59,7 @@ def _epc(
|
||||||
parts: list[SapBuildingPart] = []
|
parts: list[SapBuildingPart] = []
|
||||||
for _ in range(building_parts):
|
for _ in range(building_parts):
|
||||||
part: SapBuildingPart = object.__new__(SapBuildingPart)
|
part: SapBuildingPart = object.__new__(SapBuildingPart)
|
||||||
|
part.identifier = identifier
|
||||||
part.wall_construction = wall_construction
|
part.wall_construction = wall_construction
|
||||||
part.wall_insulation_type = wall_insulation_type
|
part.wall_insulation_type = wall_insulation_type
|
||||||
part.construction_age_band = construction_age_band
|
part.construction_age_band = construction_age_band
|
||||||
|
|
@ -148,6 +151,31 @@ def test_template_is_the_member_closest_to_the_cohort_median_size() -> None:
|
||||||
assert predicted.total_floor_area_m2 == 80.0
|
assert predicted.total_floor_area_m2 == 80.0
|
||||||
|
|
||||||
|
|
||||||
|
def test_template_skips_a_main_less_member_so_the_prediction_has_a_main_part() -> None:
|
||||||
|
# Arrange — the size-median member is OTHER-only (the gov API lodged its part
|
||||||
|
# with a null identifier), but the cohort holds MAIN-bearing neighbours at
|
||||||
|
# other sizes. The structural template must be a MAIN-bearing member so the
|
||||||
|
# predicted dwelling presents a main dwelling — else the modelling handler's
|
||||||
|
# MAIN-part guard rejects an otherwise-rich cohort as "not predictable".
|
||||||
|
cohort = _cohort(
|
||||||
|
_epc(floor_area=80.0, identifier=BuildingPartIdentifier.OTHER),
|
||||||
|
_epc(floor_area=30.0, identifier=BuildingPartIdentifier.MAIN),
|
||||||
|
_epc(floor_area=200.0, identifier=BuildingPartIdentifier.MAIN),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Act
|
||||||
|
predicted: EpcPropertyData = EpcPrediction().predict(
|
||||||
|
PredictionTarget(postcode="LS6 1AA", property_type="2"), cohort
|
||||||
|
)
|
||||||
|
|
||||||
|
# Assert — the predicted dwelling has a MAIN part (seeded from a MAIN-bearing
|
||||||
|
# neighbour), not the OTHER-only median member.
|
||||||
|
assert any(
|
||||||
|
part.identifier is BuildingPartIdentifier.MAIN
|
||||||
|
for part in predicted.sap_building_parts
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_sets_main_wall_construction_to_the_cohort_mode() -> None:
|
def test_sets_main_wall_construction_to_the_cohort_mode() -> None:
|
||||||
# Arrange — the template (members[0]) is solid brick (2), but the cohort
|
# Arrange — the template (members[0]) is solid brick (2), but the cohort
|
||||||
# majority is cavity (1). The homogeneous categorical should follow the mode,
|
# majority is cavity (1). The homogeneous categorical should follow the mode,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue