added loft_insulated_efficiency

This commit is contained in:
Khalim Conn-Kowlessar 2026-02-02 14:53:25 +00:00
parent 9c5befbff6
commit c8c283cd90
2 changed files with 42 additions and 10 deletions

View file

@ -122,8 +122,8 @@ class EpcRoofDescriptions(Enum):
# Loft
# Assumed options
pitched_insulated_assumed = "Pitched, insulated (assumed)"
# Known insulation at joists - we have 12, 25, 50, 75, 100, 125, 150, 175, 200, 225, 250, 270, 300, 350,
# 400+ as options
pitched_no_insulation = "Pitched, no insulation"
# Insulation thickness options
loft_12mm_insulation: str = "Pitched, 12 mm loft insulation"
loft_25mm_insulation: str = "Pitched, 25 mm loft insulation"
loft_50mm_insulation: str = "Pitched, 50 mm loft insulation"
@ -182,7 +182,7 @@ class EpcRoofDescriptions(Enum):
# Sloping ceiling
# For sloping ceiling tags, we don't use any (assumed) tags so that it's unambiguous that the roof is sloped
sloping_pitched_no_insulation: str = "Pithced, no insulation"
sloping_pitched_no_insulation: str = "Pitched, no insulation"
sloping_pitched_limited_insulation: str = "Pitched, limited insulation"
sloping_pitched_insulated: str = "Pitched, insulated"
@ -372,6 +372,33 @@ def flat_insulated_efficiency(age_band: EpcConstructionAgeBand) -> EpcEfficiency
pass
def loft_insulated_efficiency(age_band: EpcConstructionAgeBand) -> EpcEfficiency:
"""
2023 onwards -> Very Good
2012-2022 -> Very Good
2007-2011 -> Very Good
2003-2006 -> Very Good
1996-2002 -> Good
1991-1995 -> Good
1983-1990 -> Average
1976-1982 -> Average
1967-1975 -> Average
1950-1966 -> Average
1930-1949 -> Average
1900-1929 -> Average
before 1900 -> Average
:param age_band: Input age band, EpcConstructionAgeBand
:return: EpcEfficiency
"""
year = age_band.start_year()
if year >= 2003:
return EpcEfficiency.VERY_GOOD
if year >= 1991:
return EpcEfficiency.GOOD
return EpcEfficiency.AVERAGE
def flat_limited_efficiency(
age_band: EpcConstructionAgeBand,
insulation_thickness: int | None,
@ -407,6 +434,7 @@ ROOF_DESCRIPTION_EFFICIENCIES: Mapping[EpcRoofDescriptions, RoofEfficiencyRule]
EpcRoofDescriptions.flat_insulated: flat_insulated_efficiency,
# Loft:
# value mappings
EpcRoofDescriptions.loft_12mm_insulation: EpcEfficiency.VERY_POOR,
EpcRoofDescriptions.loft_25mm_insulation: EpcEfficiency.POOR,
EpcRoofDescriptions.loft_50mm_insulation: EpcEfficiency.POOR,
@ -421,4 +449,8 @@ ROOF_DESCRIPTION_EFFICIENCIES: Mapping[EpcRoofDescriptions, RoofEfficiencyRule]
EpcRoofDescriptions.loft_300mm_insulation: EpcEfficiency.VERY_GOOD,
EpcRoofDescriptions.loft_350mm_insulation: EpcEfficiency.VERY_GOOD,
EpcRoofDescriptions.loft_400mm_plus_insulation: EpcEfficiency.VERY_GOOD,
EpcRoofDescriptions.pitched_no_insulation: EpcEfficiency.VERY_POOR,
# function mappings
EpcRoofDescriptions.pitched_insulated_assumed: loft_insulated_efficiency,
}

View file

@ -438,7 +438,6 @@ ROOF_UNKNOWN_AGE_FALLBACK = {
"PitchedThatched": EpcRoofDescriptions.thatched_as_built_unknown,
"PitchedNormalLoftAccess": EpcRoofDescriptions.loft_as_built_unknown,
"PitchedNormalNoLoftAccess": EpcRoofDescriptions.loft_as_built_unknown,
}
@ -454,9 +453,7 @@ def fill_roof_as_built(row):
raise NotImplementedError(f"No roof classifier for roof type '{roof_type}'")
if pd.isnull(row.construction_age_band):
raise NotImplementedError(
f"Missing age band for roof classification ({roof_type})"
)
return ROOF_UNKNOWN_AGE_FALLBACK.get(roof_type)
output = classifier(row.construction_age_band)
if output is None:
@ -477,9 +474,12 @@ data["landlord_roof_description"] = data.progress_apply(
fill_roof_as_built,
axis=1,
)
for _, row in data.iterrows():
fill_roof_as_built(row)
# Sanity check
assert data["landlord_roof_description"].isnull().sum() == 0, (
"Some roof descriptions could not be resolved"
)
# TODO: 1) Map energy efficiency
# TODO: 2) Flag sloped ceilings
# Variables we want to map
# 'Org Ref', 'Address 1', 'Address 2', 'Address 3', 'Postcode', 'Type',