diff --git a/model_data/recommendations/FloorRecommendations.py b/model_data/recommendations/FloorRecommendations.py index 0604daa4..3208378f 100644 --- a/model_data/recommendations/FloorRecommendations.py +++ b/model_data/recommendations/FloorRecommendations.py @@ -3,8 +3,10 @@ from model_data.BaseUtility import BaseUtility from model_data.Property import Property from model_data.analysis.UvalueEstimations import UvalueEstimations from model_data.rdsap_tables import default_wall_thickness, age_band_data -from model_data.recommendations.recommendation_utils import r_value_per_mm_to_u_value, calculate_u_value_uplift, \ - is_diminishing_returns +from model_data.recommendations.recommendation_utils import ( + r_value_per_mm_to_u_value, calculate_u_value_uplift, is_diminishing_returns, update_lowest_selected_u_value, + get_recommended_part +) suspended_floor_insulation_parts = [ { @@ -186,6 +188,7 @@ class FloorRecommendations(BaseUtility): u_value = self._get_floors_uvalue_estimate() # Given the U-value, we recommend underfloor insulation + self.recommend_suspended_floor_insulation(u_value=u_value) def _get_floors_uvalue_estimate(self): @@ -237,7 +240,7 @@ class FloorRecommendations(BaseUtility): def recommend_suspended_floor_insulation(self, u_value): """ - This method is taskes with estimating the impact of performing suspended floor insulation + This method is tasked with estimating the impact of performing suspended floor insulation :return: """ @@ -253,6 +256,13 @@ class FloorRecommendations(BaseUtility): ): continue + if new_u_value <= self.BUILDING_REGULATIONS_PART_L_MAX_U_VALUE: + lowest_selected_u_value = update_lowest_selected_u_value(lowest_selected_u_value, new_u_value) + + self.recommendations.append( + get_recommended_part(part, depth, new_u_value) + ) + @staticmethod def _estimate_floors(floor_area, num_rooms): """ diff --git a/model_data/recommendations/WallRecommendations.py b/model_data/recommendations/WallRecommendations.py index b87e7184..f3e78e65 100644 --- a/model_data/recommendations/WallRecommendations.py +++ b/model_data/recommendations/WallRecommendations.py @@ -4,9 +4,10 @@ import math from model_data.Property import Property from model_data.analysis.UvalueEstimations import UvalueEstimations from model_data.BaseUtility import BaseUtility -from copy import deepcopy -from model_data.recommendations.recommendation_utils import r_value_per_mm_to_u_value, calculate_u_value_uplift, \ - is_diminishing_returns +from model_data.recommendations.recommendation_utils import ( + r_value_per_mm_to_u_value, calculate_u_value_uplift, is_diminishing_returns, update_lowest_selected_u_value, + get_recommended_part +) external_wall_insulation_parts = [ { @@ -329,15 +330,10 @@ class WallRecommendations(BaseUtility): # We allow a small tolerance for error so we don't discount the recommendation entirely if new_u_value <= self.BUILDING_REGULATIONS_PART_L_MAX_U_VALUE: - - if lowest_selected_u_value is None: - lowest_selected_u_value = new_u_value - - if new_u_value <= lowest_selected_u_value: - lowest_selected_u_value = new_u_value + lowest_selected_u_value = update_lowest_selected_u_value(lowest_selected_u_value, new_u_value) self.recommendations.append( - self._get_recommended_part(part, depth, new_u_value) + get_recommended_part(part, depth, new_u_value) ) # We also can recommend both internal and external wall insulation together @@ -364,8 +360,8 @@ class WallRecommendations(BaseUtility): # For now, I'm adding them as separate items in the list recommendation = [ - self._get_recommended_part(ewi_part, ewi_depth, combined_new_u_value), - self._get_recommended_part(iwi_part, iwi_depth, combined_new_u_value) + get_recommended_part(ewi_part, ewi_depth, combined_new_u_value), + get_recommended_part(iwi_part, iwi_depth, combined_new_u_value) ] self.recommendations.append(recommendation) @@ -432,22 +428,6 @@ class WallRecommendations(BaseUtility): return u_value_estimate["median_thermal_transmittance"].mean() - @staticmethod - def _get_recommended_part(part, selected_depth, new_u_value): - """ - Utility function to return a recommended part with the selected depth. - :param part: - :param selected_depth: - :param new_u_value: - :return: - """ - recommended_part = deepcopy(part) - recommended_part["depths"] = [selected_depth] - - return { - **recommended_part, "new_u_value": new_u_value, - } - @staticmethod def rvalue_per_mm(total_r_value: float, thickness_mm: float) -> float: """Return R-value per mm. diff --git a/model_data/recommendations/recommendation_utils.py b/model_data/recommendations/recommendation_utils.py index d8b51e6c..d4713bb6 100644 --- a/model_data/recommendations/recommendation_utils.py +++ b/model_data/recommendations/recommendation_utils.py @@ -1,3 +1,6 @@ +from copy import deepcopy + + def r_value_per_mm_to_u_value(depth_mm: int, r_value_per_mm: float): """ Converts R-value per mm to U-value in W/m²K. @@ -78,3 +81,35 @@ def is_diminishing_returns(recommendations, new_u_value, lowest_selected_u_value ) return is_diminishing + + +def update_lowest_selected_u_value(lowest_selected_u_value, new_u_value): + """ + Utility funciton which holds the logic for how we update the lowest selected u value + :param lowest_selected_u_value: current lowest selected u value, initialised as None + :param new_u_value: new u value to compare against + :return: + """ + if lowest_selected_u_value is None: + lowest_selected_u_value = new_u_value + + if new_u_value <= lowest_selected_u_value: + lowest_selected_u_value = new_u_value + + return lowest_selected_u_value + + +def get_recommended_part(part, selected_depth, new_u_value): + """ + Utility function to return a recommended part with the selected depth. + :param part: + :param selected_depth: + :param new_u_value: + :return: + """ + recommended_part = deepcopy(part) + recommended_part["depths"] = [selected_depth] + + return { + **recommended_part, "new_u_value": new_u_value, + }