checking hhr recommendations|

This commit is contained in:
Khalim Conn-Kowlessar 2024-06-04 16:21:45 +01:00
parent a1175c04a8
commit 1393a99b8b
4 changed files with 115 additions and 29 deletions

View file

@ -858,14 +858,6 @@ class Property:
self.floor_level = 1
return
def is_mid_floor_flat(self):
"""
Simple utility function to check if the property is a mid-floor flat
:return:
"""
return self.data["property-type"] == "Flat" and self.epc_record.original_epc["floor-level"] == "mid floor"
def set_wall_type(self):
"""
This method sets the wall type of the property, using a simple approach based on the wall description

View file

@ -970,6 +970,7 @@ async def build_mds(body: MdsRequest):
results.append({
"config_address": config["address"],
"config_postcode": config["postcode"],
"uprn": p.uprn,
"address": p.address,
"postcode": p.postcode,
"measures": package_comparison["measures"],
@ -988,6 +989,74 @@ async def build_mds(body: MdsRequest):
results = pd.DataFrame(results)
# For the different measures, we check the impact with a few debugging functions
def check_mds(results, input_properties, recommendations):
import ast
walls_check = []
hhr_check = []
for p in input_properties:
res = results[results["uprn"] == p.uprn]
wall = p.walls
heating = p.main_heating
wall_recommendation = [
x for x in res["measures"].values[0] if
x in ["internal_wall_insulation", "external_wall_insulation", "cavity_wall_insulation"]
]
hhr_recommendation = [
x for x in res["measures"].values[0] if
x in ["high_heat_retention_storage_heaters"]
]
possible_measures = [ast.literal_eval(x) for x in list(recommendations[p.id].keys())]
# Unlist them
possible_measures = [x for sublist in possible_measures for x in sublist]
possible_measures = list(set(possible_measures))
if wall_recommendation:
if len(wall_recommendation) > 1:
raise Exception("something went wrong")
wall_recommendation = wall_recommendation[0]
else:
wall_recommendation = None
hhr_recommendation = hhr_recommendation[0] if hhr_recommendation else None
walls_check.append(
{
"uprn": p.uprn,
"address": p.address,
"postcode": p.postcode,
"conservation_status": p.spatial["conservation_status"],
"is_listed_building": p.spatial["is_listed_building"],
"is_heritage_building": p.spatial["is_heritage_building"],
"wall": wall["clean_description"],
"recommendation": wall_recommendation,
"possible_measures": possible_measures,
"selected_measures": res["measures"].values[0],
}
)
hhr_check.append(
{
"uprn": p.uprn,
"address": p.address,
"postcode": p.postcode,
"heating": heating["clean_description"],
"recommendation": hhr_recommendation,
"possible_measures": possible_measures,
"selected_measures": res["measures"].values[0],
}
)
walls_check = pd.DataFrame(walls_check)
hhr_check = pd.DataFrame(hhr_check)
return walls_check, hhr_check
walls_check, hhr_check = check_mds(results, input_properties, recommendations)
results = []
for p in input_properties:
measures = p.measures

View file

@ -11,9 +11,12 @@ class HeatingRecommender:
ELECTRIC_HEATING_DESCRIPTIONS = [
"Room heaters, electric",
"Electric storage heaters",
"Electric storage heaters, radiators"
"Electric storage heaters, radiators",
"Portable electric heaters assumed for most rooms",
]
high_heat_retention_contols_desc = "Controls for high heat retention storage heaters"
def __init__(self, property_instance: Property):
self.property = property_instance
self.costs = Costs(self.property)
@ -31,12 +34,13 @@ class HeatingRecommender:
:return:
"""
no_heating_no_mains = (
self.property.main_heating["clean_description"] in ["No system present, electric heaters assumed"] and
not self.property.data["mains-gas-flag"]
# If the property has assumed electric heating, regardless of whether or not it has a mains connection, we
# can consider hhr storage heaters
electric_heating_assumed = (
self.property.main_heating["clean_description"] in ["No system present, electric heaters assumed"]
)
return self.has_electric_heating_description or no_heating_no_mains
return self.has_electric_heating_description or electric_heating_assumed
def recommend(self, has_cavity_or_loft_recommendations, phase=0):
"""
@ -330,6 +334,25 @@ class HeatingRecommender:
return output
def is_hhr_already_installed(self):
"""
Check if the property already has high heat retention storage heaters
:return:
"""
already_has_hhr = "Electric storage heaters" in self.property.main_heating["clean_description"]
already_has_hhr_contols = (
self.property.main_heating_controls[
"clean_description"
].lower() == self.high_heat_retention_contols_desc.lower()
)
# Conditions for not needing this recommendation
# Modern hhr storage heaters will have the specific controls so we can check for this
already_installed_hh_retention = already_has_hhr and already_has_hhr_contols
return already_installed_hh_retention
def recommend_hhr_storage_heaters(self, phase, system_change, heating_controls_only, _return=False):
"""
We will recommend upgrading to a high heat retention storage system, if the current system is not already
@ -346,19 +369,13 @@ class HeatingRecommender:
controls_recommender = HeatingControlRecommender(self.property)
# The heating controls we're recommending for are based on the recommended heating system
high_heat_retention_contols_desc = "Controls for high heat retention storage heaters"
# We only recommend Celect-type controls if the current heating system is not Celect-type controls
if self.property.main_heating_controls["clean_description"] != high_heat_retention_contols_desc:
if self.property.main_heating_controls["clean_description"] != self.high_heat_retention_contols_desc:
controls_recommender.recommend(heating_description="Electric storage heaters, radiators")
# Conditions for not needing this recommendation
already_installed_hh_retention = (
"Electric storage heaters" in self.property.main_heating["clean_description"] and
self.property.main_heating_controls["clean_description"].lower() == high_heat_retention_contols_desc.lower()
)
# Conditions for not recommending electric storage heaters
if already_installed_hh_retention:
if self.is_hhr_already_installed():
# No recommendation needed
return

View file

@ -116,6 +116,7 @@ class Mds:
final_combinations.append([m for m in one_choice + multi_path + remaining_measures])
pruned_combinations = []
# TODO: We can do these checks once, outside of the loop and prune the combinations
for combination in final_combinations:
pruned_measures = []
for measure in combination:
@ -142,10 +143,12 @@ class Mds:
if measure == "loft_insulation":
# Check if the roof is suitable for loft insulation and the loft isn't already done
# Or, if the home had a u-value for the roof, we don't recommend loft insulation
if (
self.property_instance.roof["is_pitched"] and
not self.roof_recommender.is_loft_already_insulated()
) or self.property_instance.is_mid_floor_flat():
not self.roof_recommender.is_loft_already_insulated() and
self.property_instance.roof["thermal_transmittance_unit"] is None
):
pruned_measures.append(measure)
continue
@ -153,8 +156,9 @@ class Mds:
# Check if the floor is solid
if (
self.property_instance.floor["is_solid"] and
self.property_instance.floor["insulation_thickness"] not in ["average", "above average"]
) or self.property_instance.is_mid_floor_flat():
self.property_instance.floor["insulation_thickness"] not in ["average", "above average"] and
self.property_instance.floor["thermal_transmittance_unit"] is not None
):
pruned_measures.append(measure)
continue
@ -162,13 +166,17 @@ class Mds:
# Check if the floor is suspended
if (
self.property_instance.floor["is_suspended"] and
self.property_instance.floor["insulation_thickness"] not in ["average", "above average"]
) or self.property_instance.is_mid_floor_flat():
self.property_instance.floor["insulation_thickness"] not in ["average", "above average"] and
self.property_instance.floor["thermal_transmittance_unit"] is not None
):
pruned_measures.append(measure)
continue
if measure == "high_heat_retention_storage_heaters":
if self.heating_recommender.is_high_heat_retention_valid():
if (
self.heating_recommender.is_high_heat_retention_valid() and
not self.heating_recommender.is_hhr_already_installed()
):
pruned_measures.append(measure)
continue