From 98a91a5a35944ab9bb1a29e2528dde80d33665f1 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Tue, 8 Oct 2024 11:14:13 +0100 Subject: [PATCH] adding simulation with default u-values to see impact on generate_scenarios_data --- etl/epc/generate_scenarios_data.py | 11 +++++++- recommendations/Recommendations.py | 5 +++- recommendations/WallRecommendations.py | 35 ++++++++++++++++++++------ 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/etl/epc/generate_scenarios_data.py b/etl/epc/generate_scenarios_data.py index 3497225c..15661d99 100644 --- a/etl/epc/generate_scenarios_data.py +++ b/etl/epc/generate_scenarios_data.py @@ -178,7 +178,7 @@ for scenario_property in scenario_properties: ) } - recommender = Recommendations(property_instance=p, materials=materials) + recommender = Recommendations(property_instance=p, materials=materials, default_u_values=True) property_recommendations = recommender.recommend() wall_recommendations = recommender.wall_recomender.recommendations @@ -286,6 +286,15 @@ model_api = ModelApi( all_predictions = model_api.predict_all(df=recommendations_scoring_data, bucket=get_settings().DATA_BUCKET) +sap_impact = pd.concat( + [ + all_predictions["sap_change_predictions"], + recommendations_scoring_data[["uprn", "sap_starting"]], + ], + axis=1 +) +sap_impact["predicted_impact"] = sap_impact["predictions"] - sap_impact["sap_starting"] + save_dataframe_to_s3_parquet( recommendations_scoring_data, "retrofit-data-dev", diff --git a/recommendations/Recommendations.py b/recommendations/Recommendations.py index 1b152238..ac7635c5 100644 --- a/recommendations/Recommendations.py +++ b/recommendations/Recommendations.py @@ -34,6 +34,7 @@ class Recommendations: materials: List, exclusions: List[str] = None, inclusions: List[str] = None, + default_u_values: bool = False, ): """ :param property_instance: Instance of the Property class, for the home associated to property_id @@ -42,12 +43,14 @@ class Recommendations: None, meaning no exclusions to be applied :param inclusions: List of specific measures of measure types to include. Defaulted to None, meaning all measures are included + :param default_u_values: Boolean, if True, the recommendations will use the default u-values for the property """ self.property_instance = property_instance self.materials = materials self.exclusions = exclusions if exclusions else [] self.inclusions = inclusions if inclusions else [] + self.default_u_values = default_u_values self.all_specific_measures = SPECIFIC_MEASURES self.all_non_invase_measures = NON_INVASIVE_SPECIFIC_MEASURES @@ -120,7 +123,7 @@ class Recommendations: non_invasive_recommendation_types = [r["type"] for r in self.property_instance.non_invasive_recommendations] # Building Fabric - self.wall_recomender.recommend(phase=phase, measures=measures) + self.wall_recomender.recommend(phase=phase, measures=measures, default_u_values=self.default_u_values) if self.wall_recomender.recommendations: property_recommendations.append(self.wall_recomender.recommendations) phase += 1 diff --git a/recommendations/WallRecommendations.py b/recommendations/WallRecommendations.py index dd5e861c..28e35584 100644 --- a/recommendations/WallRecommendations.py +++ b/recommendations/WallRecommendations.py @@ -179,7 +179,7 @@ class WallRecommendations(Definitions): return ewi_recommendations - def recommend(self, phase=0, measures=None): + def recommend(self, phase=0, measures=None, default_u_values=False): # if building built after 1990 + we're able to identify U-value + # U-value less than 0.18 and if in or close to a conversation area, # recommend internal wall insulation as a possible measure @@ -255,19 +255,19 @@ class WallRecommendations(Definitions): 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, measures) + self.find_cavity_insulation(u_value, insulation_thickness, phase, measures, default_u_values) return # Remaining wall types are treated with IWI or EWI if (u_value >= self.BUILDING_REGULATIONS_PART_L_MAX_U_VALUE) and self.is_suitable_for_solid_insulation(): - self.find_insulation(u_value, phase, measures=measures) + self.find_insulation(u_value, phase, measures=measures, default_u_values=default_u_values) return # If the u-value is within regulations, we don't do anything return - def find_cavity_insulation(self, u_value, insulation_thickness, phase, measures): + def find_cavity_insulation(self, u_value, insulation_thickness, phase, measures, default_u_values): """ This method tests different materials to fill the cavity wall, determining which material will give us the best U-value. @@ -289,6 +289,7 @@ class WallRecommendations(Definitions): filled cavity wall :param phase: The phase of the recommendation :param measures: The measures we're considering + :param default_u_values: If we should use default u values """ insulation_materials = pd.DataFrame(self.cavity_wall_insulation_materials) @@ -344,7 +345,15 @@ class WallRecommendations(Definitions): description = self._make_description(material) # updated the new u-value with the best possible our installers have - new_u_value = max(0.31, new_u_value) + if default_u_values: + new_u_value = get_wall_u_value( + clean_description="Cavity wall, filled cavity", + age_band="G", + is_granite_or_whinstone=self.property.walls["is_granite_or_whinstone"], + is_sandstone_or_limestone=self.property.walls["is_sandstone_or_limestone"], + ) + else: + new_u_value = max(0.31, new_u_value) wall_ending_config = WallAttributes("Cavity wall, filled cavity").process() @@ -359,7 +368,7 @@ class WallRecommendations(Definitions): simulation_config = { **simulation_config, **walls_simulation_config, - "walls_thermal_transmittance_ending": new_u_value, + "walls_thermal_transmittance_ending": new_u_value if not default_u_values else 0.7, } recommendations.append( @@ -439,7 +448,7 @@ class WallRecommendations(Definitions): return simulation_config - def _find_insulation(self, u_value, insulation_materials, phase): + def _find_insulation(self, u_value, insulation_materials, phase, default_u_values): lowest_selected_u_value = None recommendations = [] @@ -534,6 +543,14 @@ class WallRecommendations(Definitions): "walls_thermal_transmittance_ending": new_u_value } + if default_u_values: + new_u_value = get_wall_u_value( + clean_description=new_description, + age_band=self.property.age_band, + is_granite_or_whinstone=self.property.walls["is_granite_or_whinstone"], + is_sandstone_or_limestone=self.property.walls["is_sandstone_or_limestone"], + ) + recommendations.append( { "phase": phase, @@ -564,7 +581,7 @@ class WallRecommendations(Definitions): return recommendations - def find_insulation(self, u_value, phase, measures): + def find_insulation(self, u_value, phase, measures, default_u_values): """ 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 @@ -584,6 +601,7 @@ class WallRecommendations(Definitions): self.external_wall_insulation_materials ), phase=phase, + default_u_values=default_u_values ) iwi_recommendations = [] @@ -592,6 +610,7 @@ class WallRecommendations(Definitions): u_value=u_value, insulation_materials=pd.DataFrame(self.internal_wall_insulation_materials), phase=phase, + default_u_values=default_u_values ) self.recommendations += ewi_recommendations + iwi_recommendations