implementing eco4 indicative view

This commit is contained in:
Khalim Conn-Kowlessar 2023-12-13 12:39:25 +00:00
parent dd834d337e
commit df989ba918
2 changed files with 187 additions and 21 deletions

View file

@ -59,6 +59,8 @@ class Eligibility:
self.loft_insulation()
self.cavity_insulation()
self.tenure = self.tenure_remap.get(self.epc["tenure"], None)
def parse_fabric(self, key):
# Get the cleaned version of the description
@ -388,7 +390,6 @@ class Eligibility:
self.suspended_floor_insulation()
self.solid_floor_insulation()
tenure = self.tenure_remap.get(self.epc["tenure"], None)
current_sap = int(self.epc["current-energy-efficiency"])
is_below_e = current_sap <= 54
is_below_c = current_sap <= 68
@ -403,19 +404,19 @@ class Eligibility:
self.solid_floor["suitability"]
)
if tenure == "Rented (social)":
if self.tenure == "Rented (social)":
if is_below_c and (not is_below_e):
# this is a placeholder methodology
self.gbis = {
"eligible": int(self.epc["potential-energy-efficiency"]) > current_sap,
"message": "proxy methodology until we complete innovation measure recommendations"
"eligible": int(self.epc["potential-energy-efficiency"]) > 68,
"message": "contingent on innovation measure delivery"
}
return
elif (not is_below_c) and is_below_e:
elif is_below_e:
self.gbis = {
"eligible": needs_measure,
"message": "proxy methodology until we complete innovation measure recommendations"
"message": "eligible under fabric measure"
}
return
else:
@ -425,20 +426,20 @@ class Eligibility:
}
return
elif tenure == "Rented (private)":
elif self.tenure == "Rented (private)":
self.gbis = {
"eligible": is_below_c and needs_measure,
"message": "conditional tenant occupancy requirements and coucil tax band"
"message": "eligible under fabric measure"
}
return
elif tenure == "Owner-occupied":
elif self.tenure == "Owner-occupied":
self.gbis = {
"eligible": False,
"message": "Out-of-scope"
}
return
elif (tenure is None) or tenure == "unknown":
elif (self.tenure is None) or self.tenure == "unknown":
self.gbis = {
"eligible": needs_measure,
"message": "unknown tenure"
@ -447,8 +448,144 @@ class Eligibility:
else:
raise ValueError("Implement me other tenure types")
def check_eco4_potential(self):
def check_eco4(self):
"""
Because ECO4 supports nearly all measures, if we have commercial agreements in place then we
Because ECO4 supports nearly all measures. If we have commercial agreements in place then a large number
of homes would be eligible for eco funding, if identified.
These are the eligibility criteria we consider for this process:
Privately rented, Help to heat group
- Sap E-G
- Must receive one of solid wall insulation, first time central heating or district heating control
- The property must already have cavity walls and roof insulated
Social Housing, SAP D
- Innovation measures and insulation measures to meet the minimum insulation requirement
- Improvement to at least band C
- Fabric measures
- If receiving any heating measures, must have at least one insulation measure first
Social Housing, SAP E-G
- Insulation measures, first time central heating, renewable heating, district heating connection,
innovation measures
- Improvement to D (F & G properties) or C (E properties)
- If receiving any heating measure, must already have cavity and roof insulation
Privately rented, ECO4 Flex route 1, 2, 3, 4
- Must have SAP E-G
- Most measures eligible, but must receive one of solid wall insulation, first time central heating,
renewable heating and district heating control
- Improvement to D (F & G properties) or C (E properties)
- All homes receiving heating measures must first have insulated cavity/roof
The flex routes are given here:
https://so-eco.co.uk/what-is-eco4-flex/#:~:text=One%20way%20to%20gain%20ECO4,
including%20elderly%20residents%20and%20lodgers.
:return:
"""
self.cavity_insulation()
self.loft_insulation()
self.solid_wall_insulation()
self.room_roof_insulation()
self.flat_roof_insulation()
self.suspended_floor_insulation()
self.solid_floor_insulation()
current_sap = int(self.epc["current-energy-efficiency"])
is_below_e = current_sap <= 54
is_below_c = current_sap <= 68
sap_potential = int(self.epc["potential-energy-efficiency"])
first_time_central_heating = "boiler" not in self.epc["mainheat-description"].lower()
needs_fabric_measure = (
self.cavity["suitability"] or
self.loft["suitability"] or
self.solid_wall["suitability"] or
self.room_roof["suitability"] or
self.flat_roof["suitability"] or
self.suspended_floor["suitability"] or
self.solid_floor["suitability"]
)
if current_sap <= 38 and sap_potential >= 55:
# sap needs to get to at least a D
expected_to_meet_upgrades = True
elif current_sap <= 68 and sap_potential >= 69:
# sap needs to get to at least a C
expected_to_meet_upgrades = True
else:
expected_to_meet_upgrades = False
if self.tenure == "Rented (social)":
if is_below_c and (not is_below_e) and expected_to_meet_upgrades:
# If the property is a D, then it's eligible under innovation measures but requires improvement to a
# band C
self.eco4 = {
"eligible": True,
"message": "eligible under innovation measure and improvement to band C"
}
elif is_below_e and expected_to_meet_upgrades:
# If the property is an E or below, then it's eligible under fabric measures or heating/innovation
# measures
message = "eligible under fabric measures, with sufficient post retrofit sap improvement" if (
needs_fabric_measure) else (
"eligible under heating and innovation measures, with sufficient post retrofit sap improvement"
)
self.eco4 = {"eligible": True, "message": message}
else:
if (current_sap <= 68) and expected_to_meet_upgrades:
raise ValueError("something is wrong")
self.eco4 = {
"eligible": False,
"message": "not eligible, above EPC C"
}
return
if self.tenure == 'Rented (private)':
# For private homes, the property needs to be an E or below
# For private homes, the cavity must be filled and the roof insulated
cavity_filled = not self.cavity["suitability"]
roof_insulated = (not self.loft["suitability"]) and (not self.room_roof["suitability"]) and (
not self.flat_roof["suitability"])
if is_below_e and cavity_filled and roof_insulated and expected_to_meet_upgrades:
if self.solid_wall["suitability"]:
self.eco4 = {
"eligible": True,
"message": "eligible under solid wall insulation, conditional on post retrofit sap and help "
"to heat/ECO flex route"
}
elif first_time_central_heating:
self.eco4 = {
"eligible": True,
"message": "eligible under first time central heating, conditional on post retrofit sap and "
"help to heat/ECO flex route"
}
else:
self.eco4 = {
"eligible": False,
"message": "not eligible at this time"
}
return
else:
self.eco4 = {
"eligible": False,
"message": "not eligible at this time, EPC too high"
}
self.eco4 = {
"eligible": False,
"message": "Out of scope"
}

View file

@ -472,6 +472,8 @@ def get_ha_32data(ha_data, cleaned, cleaning_data, created_at):
"message": "No EPC found",
"gbis_eligible_future": None,
"gbis_eligible_future_message": None,
"tenure": None,
"heating_description": None,
}
)
continue
@ -503,7 +505,7 @@ def get_ha_32data(ha_data, cleaned, cleaning_data, created_at):
# If the house is not identified, we do a full gbis and eco4 check
# TODO: Add in ECO4 check
eligibility.check_gbis()
# eligibility.check_eco4()
eligibility.check_eco4()
if eligibility.eco4_warmfront["eligible"]:
scoring_dictionary = prepare_model_data_row(
@ -527,6 +529,8 @@ def get_ha_32data(ha_data, cleaned, cleaning_data, created_at):
"message": "eco4 conditional on post sap",
"gbis_eligible_future": eligibility.gbis["eligible"],
"gbis_eligible_future_message": eligibility.gbis["message"],
"tenure": eligibility.tenure,
"heating_description": eligibility.epc["mainheat-description"],
}
)
continue
@ -545,6 +549,8 @@ def get_ha_32data(ha_data, cleaned, cleaning_data, created_at):
"message": None,
"gbis_eligible_future": eligibility.gbis["eligible"],
"gbis_eligible_future_message": eligibility.gbis["message"],
"tenure": eligibility.tenure,
"heating_description": eligibility.epc["mainheat-description"],
}
)
@ -738,15 +744,28 @@ def get_ha_15data(ha_data, cleaned, cleaning_data, created_at):
eligibility_assessment = []
for _, row in results_df[results_df["eco4_eligible"] == True].iterrows():
# The upgrade requirements are dependent on the current SAP
if row["post_install_sap"] >= 71:
eligibility_classification = "highest confidence"
elif row["post_install_sap"] >= 69:
eligibility_classification = "high confidence"
elif row["post_install_sap"] >= 67:
eligibility_classification = "medium confidence"
# If the property is an F or G, it only needs to upgrade to an %
if row["sap"] <= 38:
if row["post_install_sap"] >= 57:
eligibility_classification = "highest confidence"
elif row["post_install_sap"] >= 55:
eligibility_classification = "high confidence"
elif row["post_install_sap"] >= 53:
eligibility_classification = "medium confidence"
else:
eligibility_classification = "unlikely"
else:
eligibility_classification = "unlikely"
if row["post_install_sap"] >= 71:
eligibility_classification = "highest confidence"
elif row["post_install_sap"] >= 69:
eligibility_classification = "high confidence"
elif row["post_install_sap"] >= 67:
eligibility_classification = "medium confidence"
else:
eligibility_classification = "unlikely"
eligibility_assessment.append(
{
@ -841,11 +860,19 @@ def analyse_ha_32_results(results, ha32, no_house_numbers):
(results_df["gbis_eligible"] | results_df["eco4_eligible"])
].copy()
new_possibilities_full_gbis = results_df[
(~results_df["warmfront_identified"]) &
(results_df["gbis_eligible_future"] == True)
].copy()
# We deem that Any EPC that is produced in the last 3 years gives us good confidence
cutoff_date = datetime.now() - timedelta(days=3 * 365)
new_possibilities["high_confidence"] = pd.to_datetime(new_possibilities["date_epc"]) >= cutoff_date
new_possibilities_full_gbis["high_confidence"] = pd.to_datetime(
new_possibilities_full_gbis["date_epc"]) >= cutoff_date
# We do a quick check on properties that didn't have a house number:
no_house_numbers_ha32 = ha32[ha32["row_id"].isin(no_house_numbers)]["identified"].sum()
if no_house_numbers_ha32:
@ -853,7 +880,9 @@ def analyse_ha_32_results(results, ha32, no_house_numbers):
new = {
"n_new_possibilities": new_possibilities.shape[0],
"new_possibilities_confidence": new_possibilities["high_confidence"].value_counts()
"new_possibilities_confidence": new_possibilities["high_confidence"].value_counts(),
"new_possibilities_full_gbis": new_possibilities_full_gbis.shape[0],
"new_possibilities_full_gbis_confidence": new_possibilities_full_gbis["high_confidence"].value_counts()
}
return success_rate, new