Adding in condition checks for various measures

This commit is contained in:
Khalim Conn-Kowlessar 2024-06-04 11:14:43 +01:00
parent 1c6ffd6c05
commit a5876d40db
4 changed files with 94 additions and 45 deletions

View file

@ -8,6 +8,11 @@ from recommendations.HeatingControlRecommender import HeatingControlRecommender
class HeatingRecommender:
ELECTRIC_HEATING_DESCRIPTIONS = [
"Room heaters, electric",
"Electric storage heaters",
"Electric storage heaters, radiators"
]
def __init__(self, property_instance: Property):
self.property = property_instance
@ -16,6 +21,23 @@ class HeatingRecommender:
self.heating_recommendations = []
self.heating_control_recommendations = []
self.has_electric_heating_description = (
self.property.main_heating["clean_description"] in self.ELECTRIC_HEATING_DESCRIPTIONS
)
def is_high_heat_retention_valid(self):
"""
Check conditions if high heat retention storage is valid
: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"]
)
return self.has_electric_heating_description or no_heating_no_mains
def recommend(self, has_cavity_or_loft_recommendations, phase=0):
"""
Produces heating recommendations
@ -34,16 +56,7 @@ class HeatingRecommender:
# This first iteration of the recommender will provide very basic recommendation
# We recommend heating controls based on the main heating system
has_electric_heating_description = self.property.main_heating["clean_description"] in [
"Room heaters, electric", "Electric storage heaters", "Electric storage heaters, radiators"
]
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 has_electric_heating_description or no_heating_no_mains:
if self.is_high_heat_retention_valid():
# Recommend high heat retention storage heaters
self.recommend_hhr_storage_heaters(phase=phase, system_change=True, heating_controls_only=False)
@ -61,7 +74,7 @@ class HeatingRecommender:
)
# We also check if the property has electric heating, but it has access to the mains gas
electic_heating_has_mains = has_electric_heating_description and self.property.data["mains-gas-flag"]
electic_heating_has_mains = self.has_electric_heating_description and self.property.data["mains-gas-flag"]
portable_heaters_has_mains = (
self.property.main_heating["clean_description"] in ["Portable electric heaters assumed for most rooms"] and
@ -93,16 +106,19 @@ class HeatingRecommender:
# In the future, we'll allow overrides, so that non-intrusive surveys can contradict these conditions
# and either allow or prevent the recommendation of an air source heat pump
suitable_property_type = self.property.data["property-type"] in ["House", "Bungalow"]
has_air_source_heat_pump = self.property.main_heating["has_air_source_heat_pump"]
if suitable_property_type and not has_air_source_heat_pump:
if self.is_ashp_valid():
self.recommend_air_source_heat_pump(
phase=phase, has_cavity_or_loft_recommendations=has_cavity_or_loft_recommendations
)
return
def is_ashp_valid(self):
suitable_property_type = self.property.data["property-type"] in ["House", "Bungalow"]
has_air_source_heat_pump = self.property.main_heating["has_air_source_heat_pump"]
return suitable_property_type and not has_air_source_heat_pump
def recommend_air_source_heat_pump(self, phase, has_cavity_or_loft_recommendations, _return=False):
"""
This method will implement the recommendation for an air source heat pump

View file

@ -123,36 +123,58 @@ class Mds:
continue
# There are certain measures where we need to
if measure == "external_wall_insulation":
# Check if the wall is solid
if self.property_instance.walls['is_solid_brick']:
# Check if the wall is not cavity since the other wall types can take external wall insulation
if self.wall_recommender.ewi_valid():
pruned_measures.append(measure)
continue
if measure == "cavity_wall_insulation":
# Check if the wall is cavity
if self.property_instance.walls['is_cavity_wall']:
if (
self.property_instance.walls['is_cavity_wall'] and
not self.property_instance.walls['is_filled_cavity']
):
pruned_measures.append(measure)
continue
if measure == "loft_insulation":
# Check if the roof is suitable for loft insulation
if self.property_instance.roof["is_pitched"]:
# Check if the roof is suitable for loft insulation and the loft isn't already done
if (
self.property_instance.roof["is_pitched"] and
not self.roof_recommender.is_loft_already_insulated()
):
pruned_measures.append(measure)
continue
if measure == "solid_floor_insulation":
# Check if the floor is solid
if self.property_instance.floor["is_solid"]:
if (
self.property_instance.floor["is_solid"] and
self.property_instance.floor["insulation_thickness"] not in ["average", "above average"]
):
pruned_measures.append(measure)
continue
if measure == "suspended_floor_insulation":
# Check if the floor is suspended
if self.property_instance.floor["is_suspended"]:
if (
self.property_instance.floor["is_suspended"] and
self.property_instance.floor["insulation_thickness"] not in ["average", "above average"]
):
pruned_measures.append(measure)
continue
pruned_measures.append(measure)
if measure == "high_heat_retention_storage_heaters":
if self.heating_recommender.is_high_heat_retention_valid():
pruned_measures.append(measure)
continue
if measure == "air_source_heat_pump":
if self.heating_recommender.is_ashp_valid():
pruned_measures.append(measure)
continue
raise NotImplementedError("Implement me")
pruned_measures_formatted = []
for pm in pruned_measures:
@ -311,7 +333,6 @@ class Mds:
if self.optimise_measures:
measures_set = self.select_optimal_measure_set(self.property_instance.measures)
logger.info(f"Building recommendations for {len(measures_set)} combinations of measures")
mds_recommendations_map = {}
representative_recommendations_map = {}
errors_map = {}

View file

@ -54,6 +54,13 @@ class RoofRecommendations:
]
]
# Extract the insulation thickness from the roof, which is used throughout this method
self.insulation_thickness = convert_thickness_to_numeric(
self.property.roof["insulation_thickness"],
self.property.roof["is_pitched"],
self.property.roof["is_flat"]
)
def mds_loft_insulation(self, phase):
"""
For usages within the mds report
@ -62,18 +69,18 @@ class RoofRecommendations:
"""
self.recommendations = []
insulation_thickness = convert_thickness_to_numeric(
self.property.roof["insulation_thickness"],
self.property.roof["is_pitched"],
self.property.roof["is_flat"]
)
u_value = get_roof_u_value(**{**self.property.roof, "age_band": self.property.age_band})
self.recommend_roof_insulation(u_value, insulation_thickness, self.property.roof, phase)
self.recommend_roof_insulation(u_value, self.insulation_thickness, self.property.roof, phase)
return self.recommendations
def is_loft_already_insulated(self):
"""
Check if the loft is already insulated
"""
return (self.insulation_thickness > self.MINIMUM_LOFT_ISULATION_MM) and self.property.roof["is_pitched"]
def recommend(self, phase):
if self.property.roof["has_dwelling_above"]:
@ -81,21 +88,15 @@ class RoofRecommendations:
u_value = self.property.roof["thermal_transmittance"]
insulation_thickness = convert_thickness_to_numeric(
self.property.roof["insulation_thickness"],
self.property.roof["is_pitched"],
self.property.roof["is_flat"]
)
# We check if the roof is already insulated and if so, we exit
# Building regulations part L recommend installing at least 270mm of insulation, however generally we
# experience diminishing returns in terms of SAP once we go beyond around 150mm of insulation
# This only holds true for pitched roofs.
if (insulation_thickness > self.MINIMUM_LOFT_ISULATION_MM) and self.property.roof["is_pitched"]:
if self.is_loft_already_insulated():
return
if (insulation_thickness >= self.MINIMUM_FLAT_ROOF_ISULATION_MM) and self.property.roof["is_flat"]:
if (self.insulation_thickness >= self.MINIMUM_FLAT_ROOF_ISULATION_MM) and self.property.roof["is_flat"]:
return
if self.property.roof["is_roof_room"]:
@ -119,7 +120,7 @@ class RoofRecommendations:
return
if self.property.roof["is_pitched"] or self.property.roof["is_flat"]:
self.recommend_roof_insulation(u_value, insulation_thickness, self.property.roof, phase)
self.recommend_roof_insulation(u_value, self.insulation_thickness, self.property.roof, phase)
return
if self.property.roof["is_roof_room"]:

View file

@ -112,11 +112,9 @@ class WallRecommendations(Definitions):
self.external_wall_non_insulation_materials = [
part
for part in materials
if part["type"]
in ["ewi_wall_demolition", "ewi_wall_preparation", "ewi_wall_redecoration"]
if part["type"] in ["ewi_wall_demolition", "ewi_wall_preparation", "ewi_wall_redecoration"]
]
@property
def ewi_valid(self):
"""
This method check available data, to determine if a property is suitable for external wall insulation
@ -126,11 +124,24 @@ class WallRecommendations(Definitions):
# it is not suitable for EWI
if self.property.restricted_measures or (
self.property.data["property-type"].lower() == "flat"
) or (
self.property.walls['is_cob'] or
self.property.walls['is_sandstone_or_limestone'] or
self.property.walls["is_cavity_wall"]
):
return False
return True
def is_suitable_for_solid_insulation(self):
"""
Checks if the wall is of a suitable type for internal/external wall insulation
"""
if self.property.walls["is_cavity_wall"] or self.property.walls["is_cob"]:
return False
return True
def mds_recommend_cavity_wall_insulation(self, phase=None):
# Function specifically for cavity wall insulation, for usage in the mds report
self.recommendations = []
@ -249,7 +260,7 @@ class WallRecommendations(Definitions):
return
# Remaining wall types are treated with IWI or EWI
if u_value >= self.BUILDING_REGULATIONS_PART_L_MAX_U_VALUE:
if (u_value >= self.BUILDING_REGULATIONS_PART_L_MAX_U_VALUE) and self.is_suitable_for_solid_insulation():
self.find_insulation(u_value, phase)
return
@ -528,7 +539,7 @@ class WallRecommendations(Definitions):
# consider diminishing returns between the two as they are considered to be separate measures
ewi_recommendations = []
if self.ewi_valid:
if self.ewi_valid():
ewi_recommendations = self._find_insulation(
u_value=u_value,
insulation_materials=pd.DataFrame(