From efbcd0f0b8a2ac357a04ffe621694d63bdca9481 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Thu, 5 Sep 2024 13:36:27 +0100 Subject: [PATCH] adding measures into individual measures classes wip --- backend/app/plan/schemas.py | 5 ++- recommendations/Recommendations.py | 35 +++++++++---------- recommendations/RoofRecommendations.py | 17 +++++---- recommendations/VentilationRecommendations.py | 5 ++- recommendations/WallRecommendations.py | 18 +++++----- 5 files changed, 43 insertions(+), 37 deletions(-) diff --git a/backend/app/plan/schemas.py b/backend/app/plan/schemas.py index 5487caad..2968babf 100644 --- a/backend/app/plan/schemas.py +++ b/backend/app/plan/schemas.py @@ -37,12 +37,15 @@ SPECIFIC_MEASURES = [ "trickle_vents", "draught_proofing", "mixed_glazing", # This covers partial double glazing and secondary glazing + "cavity_extract_and_refill", ] # This allows us to extend high level categories for measures such as "wall_insulation" to the specific measures # such as "external_wall_insulation", "internal_wall_insulation", "cavity_wall_insulation" MEASURE_MAP = { - "wall_insulation": ["internal_wall_insulation", "external_wall_insulation", "cavity_wall_insulation"], + "wall_insulation": [ + "internal_wall_insulation", "external_wall_insulation", "cavity_wall_insulation", "cavity_extract_and_refill" + ], "roof_insulation": ["loft_insulation", "flat_roof_insulation", "room_roof_insulation"], "floor_insulation": ["suspended_floor_insulation", "solid_floor_insulation"], "heating": ["boiler_upgrade", "high_heat_retention_storage_heater", "air_source_heat_pump"], diff --git a/recommendations/Recommendations.py b/recommendations/Recommendations.py index a5b9d454..34586e01 100644 --- a/recommendations/Recommendations.py +++ b/recommendations/Recommendations.py @@ -71,6 +71,9 @@ class Recommendations: Determines the set of measures to be included in recommendations """ + if self.property_instance.non_invasive_recommendations: + raise Exception("IMPLEMENT ME") + inclusions_full = [MEASURE_MAP[x] if x in MEASURE_MAP else x for x in self.inclusions] exclusions_full = [MEASURE_MAP[x] if x in MEASURE_MAP else x for x in self.exclusions] @@ -96,24 +99,19 @@ class Recommendations: property_recommendations = [] phase = 0 + # TODO: We should form measures form non-intrusive recommendations too measures = self.find_included_measures() # Building Fabric - if ( - ("wall_insulation" in measures) or - ("internal_wall_insulation" in measures) or - ("external_wall_insulation" in measures) - ): - self.wall_recomender.recommend(phase=phase, measures=measures) - if self.wall_recomender.recommendations: - property_recommendations.append(self.wall_recomender.recommendations) - phase += 1 + self.wall_recomender.recommend(phase=phase, measures=measures) + if self.wall_recomender.recommendations: + property_recommendations.append(self.wall_recomender.recommendations) + phase += 1 - if "roof_insulation" in measures: - self.roof_recommender.recommend(phase=phase) - if self.roof_recommender.recommendations: - property_recommendations.append(self.roof_recommender.recommendations) - phase += 1 + self.roof_recommender.recommend(phase=phase, measures=measures) + if self.roof_recommender.recommendations: + property_recommendations.append(self.roof_recommender.recommendations) + phase += 1 # Ventilation recommendations # We only produce a ventilation recommendation if the property is recommended to have wall or roof @@ -123,11 +121,10 @@ class Recommendations: # real impact on the SAP score. Therefore, we don't need to include phasing for ventilation. If we # have any # wall or roof recommendations, we will ensure that ventilation is included in the simulation - if "ventilation" in measures: - if self.wall_recomender.recommendations or self.roof_recommender.recommendations: - self.ventilation_recomender.recommend() - if self.ventilation_recomender.recommendation: - property_recommendations.append(self.ventilation_recomender.recommendation) + if self.wall_recomender.recommendations or self.roof_recommender.recommendations: + self.ventilation_recomender.recommend(measures=measures) + if self.ventilation_recomender.recommendation: + property_recommendations.append(self.ventilation_recomender.recommendation) if "floor_insulation" in measures: self.floor_recommender.recommend(phase=phase) diff --git a/recommendations/RoofRecommendations.py b/recommendations/RoofRecommendations.py index 5075928e..8878b465 100644 --- a/recommendations/RoofRecommendations.py +++ b/recommendations/RoofRecommendations.py @@ -1,6 +1,7 @@ import math import pandas as pd from backend.Property import Property +from backend.app.plan.schemas import MEASURE_MAP from typing import List from datatypes.enums import QuantityUnits from recommendations.recommendation_utils import ( @@ -108,11 +109,13 @@ class RoofRecommendations: return full_insulated_room_roof or room_roof_insulated_at_rafters - def recommend(self, phase): + def recommend(self, phase, measures=None): if self.property.roof["has_dwelling_above"]: return + measures = MEASURE_MAP["roof_insulation"] if measures is None else measures + u_value = self.property.roof["thermal_transmittance"] # We check if the roof is already insulated and if so, we exit @@ -153,19 +156,19 @@ class RoofRecommendations: self.estimated_u_value = u_value if (u_value <= self.BUILDING_REGULATIONS_PART_L_MAX_U_VALUE) and ( - "loft_insulation" not in self.property.non_invasive_recommendations + "loft_insulation" not in measures ): # The Roof is already compliant return - if self.property.roof["is_pitched"] or self.property.roof["is_flat"]: - insulation_thickness = ( - 0 if "loft_insulation" not in self.property.non_invasive_recommendations else self.insulation_thickness - ) + if (self.property.roof["is_pitched"] and "loft_insulation" in measures) or ( + self.property.roof["is_flat"] and "flat_roof_insulation" + ): + insulation_thickness = 0 if "loft_insulation" not in measures else self.insulation_thickness self.recommend_roof_insulation(u_value, insulation_thickness, self.property.roof, phase) return - if self.property.roof["is_roof_room"]: + if self.property.roof["is_roof_room"] and ("room_roof_insulation" in measures): self.recommend_room_roof_insulation(u_value, phase) return diff --git a/recommendations/VentilationRecommendations.py b/recommendations/VentilationRecommendations.py index 1120654a..4f88b953 100644 --- a/recommendations/VentilationRecommendations.py +++ b/recommendations/VentilationRecommendations.py @@ -29,7 +29,7 @@ class VentilationRecommendations(Definitions): def identify_ventilation(self): self.has_ventilaion = self.property.data["mechanical-ventilation"] in self.VENTILATION_DESCRIPTIONS - def recommend(self): + def recommend(self, measures=None): """ If there is no ventilation, we recommend installing ventilation @@ -37,6 +37,9 @@ class VentilationRecommendations(Definitions): ventilation if there is natural ventilation :return: """ + measures = ["ventilation"] if measures is None else measures + if "ventilation" not in measures: + return self.identify_ventilation() if self.has_ventilaion: diff --git a/recommendations/WallRecommendations.py b/recommendations/WallRecommendations.py index 43727517..18e269ab 100644 --- a/recommendations/WallRecommendations.py +++ b/recommendations/WallRecommendations.py @@ -5,6 +5,7 @@ import pandas as pd from datatypes.enums import QuantityUnits from backend.Property import Property +from backend.app.plan.schemas import MEASURE_MAP from BaseUtility import Definitions from etl.epc_clean.epc_attributes.WallAttributes import WallAttributes from recommendations.recommendation_utils import ( @@ -195,6 +196,10 @@ class WallRecommendations(Definitions): # U-value less than 0.18 and if in or close to a conversation area, # recommend internal wall insulation as a possible measure + measures = MEASURE_MAP["wall_insulation"] if measures is None else measures + if not measures: + return + u_value = self.property.walls["thermal_transmittance"] u_value = None if pd.isnull(u_value) else u_value @@ -235,7 +240,7 @@ class WallRecommendations(Definitions): and (u_value >= self.BUILDING_REGULATIONS_PART_L_MAX_U_VALUE) ): # Recommend insulation - self.find_insulation(u_value, phase) + self.find_insulation(u_value, phase, measures) return # We can't detect it's a cavity wall, but it was built after 1990 so likely built with insulation already @@ -259,7 +264,7 @@ class WallRecommendations(Definitions): self.estimated_u_value = u_value - if is_cavity_wall or "cavity_extract_and_refill" in self.property.non_invasive_recommendations: + if (is_cavity_wall and "cavity_wall_insulation" in measures) or "cavity_extract_and_refill" in measures: if u_value >= self.BUILDING_REGULATIONS_PART_L_MAX_U_VALUE: # Test filling cavity self.find_cavity_insulation(u_value, insulation_thickness, phase) @@ -558,7 +563,7 @@ class WallRecommendations(Definitions): return recommendations - def find_insulation(self, u_value, phase, measures=None): + def find_insulation(self, u_value, phase, measures): """ This function contains the logic for finding potential insulation measures for a property, depending on the parts available and whether the property can have external wall insulation installed @@ -570,13 +575,8 @@ class WallRecommendations(Definitions): # we separate the logic for for recommending them, therefore we don't # consider diminishing returns between the two as they are considered to be separate measures - if measures is None: - ewi_valid = self.ewi_valid() - else: - ewi_valid = self.ewi_valid() and "external_wall_insulation" in measures - ewi_recommendations = [] - if ewi_valid: + if self.ewi_valid() and "external_wall_insulation" in measures: ewi_recommendations = self._find_insulation( u_value=u_value, insulation_materials=pd.DataFrame(