mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Adding in condition checks for various measures
This commit is contained in:
parent
1c6ffd6c05
commit
a5876d40db
4 changed files with 94 additions and 45 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 = {}
|
||||
|
|
|
|||
|
|
@ -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"]:
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue