mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-07-27 23:35:01 +00:00
Resolve a measured sloping-ceiling depth to its ladder member 🟩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a717ff7a99
commit
02a71feae1
1 changed files with 48 additions and 2 deletions
|
|
@ -11,19 +11,65 @@ from domain.epc.property_overrides.roof_type import RoofType
|
|||
# family, never the loft ladder (ADR-0066).
|
||||
_SLOPING_CEILING_TOKEN = "pitchedwithslopingceiling"
|
||||
|
||||
# The measured-depth ladder (Table 17 col (1a) tabulated thicknesses), ascending.
|
||||
# A lodged depth snaps to the nearest tabulated depth ≤ N — mirroring the
|
||||
# calculator's `_ROOF_BY_THICKNESS` picker — so an off-ladder value never leaks
|
||||
# back to the loft LLM route. `400+` / any depth > 400 is the top member.
|
||||
_DEPTH_LADDER: list[tuple[int, RoofType]] = [
|
||||
(12, RoofType.PITCHED_SLOPING_CEILING_12MM),
|
||||
(25, RoofType.PITCHED_SLOPING_CEILING_25MM),
|
||||
(50, RoofType.PITCHED_SLOPING_CEILING_50MM),
|
||||
(75, RoofType.PITCHED_SLOPING_CEILING_75MM),
|
||||
(100, RoofType.PITCHED_SLOPING_CEILING_100MM),
|
||||
(125, RoofType.PITCHED_SLOPING_CEILING_125MM),
|
||||
(150, RoofType.PITCHED_SLOPING_CEILING_150MM),
|
||||
(175, RoofType.PITCHED_SLOPING_CEILING_175MM),
|
||||
(200, RoofType.PITCHED_SLOPING_CEILING_200MM),
|
||||
(225, RoofType.PITCHED_SLOPING_CEILING_225MM),
|
||||
(250, RoofType.PITCHED_SLOPING_CEILING_250MM),
|
||||
(270, RoofType.PITCHED_SLOPING_CEILING_270MM),
|
||||
(300, RoofType.PITCHED_SLOPING_CEILING_300MM),
|
||||
(350, RoofType.PITCHED_SLOPING_CEILING_350MM),
|
||||
(400, RoofType.PITCHED_SLOPING_CEILING_400MM),
|
||||
]
|
||||
_TOP_TABULATED_MM = 400
|
||||
|
||||
|
||||
def _normalise_roof_token(description: str) -> str:
|
||||
token = description.split(":", 1)[0]
|
||||
return re.sub(r"[^a-z0-9]", "", token.lower())
|
||||
|
||||
|
||||
def _member_for_depth(insulation: str) -> Optional[RoofType]:
|
||||
"""The ladder member for a lodged insulation suffix, or None when it carries
|
||||
no measured depth (`As Built` / `Unknown` / empty) so the caller folds it to
|
||||
`as built`. An explicit `+` or any depth above 400 mm → the 400+ member; an
|
||||
off-ladder depth snaps to the nearest tabulated depth ≤ N; a depth below the
|
||||
ladder (< 12 mm) has no member and also folds to `as built`."""
|
||||
digits = re.search(r"\d+", insulation)
|
||||
if digits is None:
|
||||
return None
|
||||
depth_mm = int(digits.group())
|
||||
if "+" in insulation or depth_mm > _TOP_TABULATED_MM:
|
||||
return RoofType.PITCHED_SLOPING_CEILING_400_PLUS
|
||||
member: Optional[RoofType] = None
|
||||
for tabulated_mm, ladder_member in _DEPTH_LADDER:
|
||||
if depth_mm >= tabulated_mm:
|
||||
member = ladder_member
|
||||
return member
|
||||
|
||||
|
||||
def roof_sloping_ceiling_guard(description: str) -> Optional[RoofType]:
|
||||
"""Deterministically resolve a `PitchedWithSlopingCeiling` roof description to
|
||||
its `Pitched, sloping ceiling, …` RoofType member (ADR-0066).
|
||||
|
||||
Returns None for anything that is not a sloping-ceiling marker, so the
|
||||
A measured depth resolves to its ladder member (nearest tabulated depth ≤ N;
|
||||
`400+` / above-400 → the 400+ member); `As Built` / `Unknown` / a sub-ladder
|
||||
depth / no suffix fold to `as built`, which defers the U-value to the age
|
||||
band. Returns None for anything that is not a sloping-ceiling marker, so the
|
||||
party-ceiling guard and the LLM classifier still handle the rest.
|
||||
"""
|
||||
if _normalise_roof_token(description) != _SLOPING_CEILING_TOKEN:
|
||||
return None
|
||||
return RoofType.PITCHED_SLOPING_CEILING_AS_BUILT
|
||||
_, _, insulation = description.partition(":")
|
||||
return _member_for_depth(insulation) or RoofType.PITCHED_SLOPING_CEILING_AS_BUILT
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue