From 925a6c1887cb11c16e231167923a286fdc552f7b Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Wed, 14 Feb 2024 12:00:49 +0000 Subject: [PATCH] Added phasing figures into recommender --- recommendations/FireplaceRecommendations.py | 3 +- recommendations/FloorRecommendations.py | 8 +-- recommendations/LightingRecommendations.py | 3 +- recommendations/Recommendations.py | 54 +++++++++++-------- recommendations/RoofRecommendations.py | 12 +++-- recommendations/SolarPvRecommendations.py | 21 ++------ recommendations/VentilationRecommendations.py | 1 + recommendations/WallRecommendations.py | 20 ++++--- recommendations/WindowsRecommendations.py | 3 +- 9 files changed, 66 insertions(+), 59 deletions(-) diff --git a/recommendations/FireplaceRecommendations.py b/recommendations/FireplaceRecommendations.py index c193b7ce..5d620d49 100644 --- a/recommendations/FireplaceRecommendations.py +++ b/recommendations/FireplaceRecommendations.py @@ -20,7 +20,7 @@ class FireplaceRecommendations(Definitions): self.has_ventilaion = None self.recommendation = None - def recommend(self): + def recommend(self, phase=0): """ Based on the number of open fireplcaes found, we recommend sealing each one at a cost of around £500 @@ -37,6 +37,7 @@ class FireplaceRecommendations(Definitions): # We recommend installing two mechanical ventilation systems self.recommendation = [ { + "phase": phase, "parts": [], "type": "sealing_open_fireplace", "description": "Seal %s open fireplaces" % str(number_open_fireplaces), diff --git a/recommendations/FloorRecommendations.py b/recommendations/FloorRecommendations.py index 2f568264..a19ee025 100644 --- a/recommendations/FloorRecommendations.py +++ b/recommendations/FloorRecommendations.py @@ -69,7 +69,7 @@ class FloorRecommendations(Definitions): # TODO: To be completed self.exposed_floor_non_insulation_materials = [] - def recommend(self): + def recommend(self, phase=0): u_value = self.property.floor["thermal_transmittance"] property_type = self.property.data["property-type"] @@ -129,7 +129,8 @@ class FloorRecommendations(Definitions): self.recommend_floor_insulation( u_value=u_value, insulation_materials=self.solid_floor_insulation_materials, - non_insulation_materials=self.solid_floor_non_insulation_materials + non_insulation_materials=self.solid_floor_non_insulation_materials, + phase=phase ) return @@ -156,7 +157,7 @@ class FloorRecommendations(Definitions): raise ValueError("Invalid material type - implement me!") - def recommend_floor_insulation(self, u_value, insulation_materials, non_insulation_materials): + def recommend_floor_insulation(self, u_value, insulation_materials, non_insulation_materials, phase): """ This method is tasked with estimating the impact of performing suspended floor insulation :return: @@ -198,6 +199,7 @@ class FloorRecommendations(Definitions): self.recommendations.append( { + "phase": phase, "parts": [ get_recommended_part( part=material.to_dict(), diff --git a/recommendations/LightingRecommendations.py b/recommendations/LightingRecommendations.py index 788d1ad1..6d50f0a2 100644 --- a/recommendations/LightingRecommendations.py +++ b/recommendations/LightingRecommendations.py @@ -51,7 +51,7 @@ class LightingRecommendations: return total_energy_savings_per_year, carbon_reduction_tonnes - def recommend(self): + def recommend(self, phase=0): """ This method will check if there are any lighting fittings that aren't low energy. @@ -90,6 +90,7 @@ class LightingRecommendations: self.recommendation = [ { + "phase": phase, "parts": [], "type": "low_energy_lighting", "description": description, diff --git a/recommendations/Recommendations.py b/recommendations/Recommendations.py index 6ca7badb..b4b764c2 100644 --- a/recommendations/Recommendations.py +++ b/recommendations/Recommendations.py @@ -51,48 +51,58 @@ class Recommendations: """ property_recommendations = [] - - # Floor recommendations - self.floor_recommender.recommend() - if self.floor_recommender.recommendations: - property_recommendations.append(self.floor_recommender.recommendations) - + phase = 0 # Wall recommendations - self.wall_recomender.recommend() + self.wall_recomender.recommend(phase=phase) if self.wall_recomender.recommendations: property_recommendations.append(self.wall_recomender.recommendations) - - # Roof recommendations - self.roof_recommender.recommend() - 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 insulation + # We will not attribute a SAP impact to the ventilation recommendation, since we've seen that this has no + # 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 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) - # Fireplace sealing recommendations - self.fireplace_recommender.recommend() - if self.fireplace_recommender.recommendation: - property_recommendations.append(self.fireplace_recommender.recommendation) + # Roof recommendations + self.roof_recommender.recommend(phase=phase) + if self.roof_recommender.recommendations: + property_recommendations.append(self.roof_recommender.recommendations) + phase += 1 - # Lighting recommendations - self.lighting_recommender.recommend() - if self.lighting_recommender.recommendation: - property_recommendations.append(self.lighting_recommender.recommendation) + # Floor recommendations + self.floor_recommender.recommend(phase=phase) + if self.floor_recommender.recommendations: + property_recommendations.append(self.floor_recommender.recommendations) + phase += 1 # Windows recommendations - self.windows_recommender.recommend() + self.windows_recommender.recommend(phase=phase) if self.windows_recommender.recommendation: property_recommendations.append(self.windows_recommender.recommendation) + phase += 1 + + # Fireplace sealing recommendations + self.fireplace_recommender.recommend(phase=phase) + if self.fireplace_recommender.recommendation: + property_recommendations.append(self.fireplace_recommender.recommendation) + phase += 1 + + # Lighting recommendations + self.lighting_recommender.recommend(phase=phase) + if self.lighting_recommender.recommendation: + property_recommendations.append(self.lighting_recommender.recommendation) + phase += 1 # Solar recommendations - self.solar_recommender.recommend() + self.solar_recommender.recommend(phase=phase) if self.solar_recommender.recommendation: property_recommendations.append(self.solar_recommender.recommendation) + phase += 1 # We insert temporary ids into the recommendations which is important for the optimiser later property_recommendations = self.insert_temp_recommendation_id(property_recommendations) diff --git a/recommendations/RoofRecommendations.py b/recommendations/RoofRecommendations.py index 0bbfd69d..eb1c6c4f 100644 --- a/recommendations/RoofRecommendations.py +++ b/recommendations/RoofRecommendations.py @@ -53,7 +53,7 @@ class RoofRecommendations: ] ] - def recommend(self): + def recommend(self, phase): if self.property.roof["has_dwelling_above"]: return @@ -98,11 +98,11 @@ 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) + self.recommend_roof_insulation(u_value, insulation_thickness, self.property.roof, phase) return if self.property.roof["is_roof_room"]: - self.recommend_room_roof_insulation(u_value) + self.recommend_room_roof_insulation(u_value, phase) return raise NotImplementedError("Implement me") @@ -124,7 +124,7 @@ class RoofRecommendations: raise ValueError("Invalid material type") def recommend_roof_insulation( - self, u_value, insulation_thickness, roof + self, u_value, insulation_thickness, roof, phase ): """ @@ -217,6 +217,7 @@ class RoofRecommendations: recommendations.append( { + "phase": phase, "parts": [ get_recommended_part( part=material.to_dict(), @@ -236,7 +237,7 @@ class RoofRecommendations: self.recommendations = recommendations - def recommend_room_roof_insulation(self, u_value): + def recommend_room_roof_insulation(self, u_value, phase): """ This method recommends room in roof insulation for properties that have been identified to possess a room in roof. @@ -314,6 +315,7 @@ class RoofRecommendations: recommendations.append( { + "phase": phase, "parts": [ get_recommended_part( part=material, diff --git a/recommendations/SolarPvRecommendations.py b/recommendations/SolarPvRecommendations.py index 9995bbe1..5fae09b3 100644 --- a/recommendations/SolarPvRecommendations.py +++ b/recommendations/SolarPvRecommendations.py @@ -18,7 +18,7 @@ class SolarPvRecommendations: self.recommendation = [] - def recommend(self): + def recommend(self, phase): """ We check if a property is potentially suitable for solar PV based on the following criteria: - The property is a house or bungalow @@ -77,6 +77,7 @@ class SolarPvRecommendations: self.recommendation.append( { + "phase": phase, "parts": [], "type": "solar_pv", "description": description, @@ -86,22 +87,6 @@ class SolarPvRecommendations: **cost_result, # This is required for simulating the SAP impact. solar_pv_percentage is between 0 & 1 so we scale # back up here - "photo_supply": 100 * scenario + "photo_supply": 100 * roof_coverage } ) - - self.recommendation = [ - { - "parts": [], - "type": "solar_pv", - "description": f"Install a {kw} kilowatt-peak (kWp) solar photovoltaic (PV) panel system on " - f"{roof_coverage_percent}% the roof", - "starting_u_value": None, - "new_u_value": None, - "sap_points": None, - **cost_result, - # This is required for simulating the SAP impact. solar_pv_percentage is between 0 & 1 so we scale - # back up here - "photo_supply": 100 * self.property.solar_pv_percentage - } - ] diff --git a/recommendations/VentilationRecommendations.py b/recommendations/VentilationRecommendations.py index 6c61f27c..7241cdec 100644 --- a/recommendations/VentilationRecommendations.py +++ b/recommendations/VentilationRecommendations.py @@ -62,6 +62,7 @@ class VentilationRecommendations(Definitions): # We recommend installing two mechanical ventilation systems self.recommendation = [ { + "phase": None, "parts": part, "type": part[0]["type"], "description": f"Install {n_units} {part[0]['description']} units", diff --git a/recommendations/WallRecommendations.py b/recommendations/WallRecommendations.py index 6e2d64ec..467c6ad3 100644 --- a/recommendations/WallRecommendations.py +++ b/recommendations/WallRecommendations.py @@ -97,7 +97,7 @@ class WallRecommendations(Definitions): return True - def recommend(self): + def recommend(self, phase=0): # 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 @@ -146,19 +146,19 @@ class WallRecommendations(Definitions): if is_cavity_wall: if u_value >= self.BUILDING_REGULATIONS_PART_L_MAX_U_VALUE: # Test filling cavity - self.find_cavity_insulation(u_value, insulation_thickness) + self.find_cavity_insulation(u_value, insulation_thickness, phase) return # Remaining wall types are treated with IWI or EWI if u_value >= self.BUILDING_REGULATIONS_PART_L_MAX_U_VALUE: - self.find_insulation(u_value) + self.find_insulation(u_value, phase) return # If the u-value is within regulations, we don't do anything return - def find_cavity_insulation(self, u_value, insulation_thickness): + def find_cavity_insulation(self, u_value, insulation_thickness, phase): """ This method tests different materials to fill the cavity wall, determining which material will give us the best U-value. @@ -210,6 +210,7 @@ class WallRecommendations(Definitions): recommendations.append( { + "phase": phase, "parts": [ get_recommended_part( part=material.to_dict(), @@ -229,7 +230,7 @@ class WallRecommendations(Definitions): self.recommendations = recommendations - def _find_insulation(self, u_value, insulation_materials, non_insulation_materials): + def _find_insulation(self, u_value, insulation_materials, non_insulation_materials, phase): lowest_selected_u_value = None recommendations = [] @@ -274,6 +275,7 @@ class WallRecommendations(Definitions): recommendations.append( { + "phase": phase, "parts": [ get_recommended_part( part=material.to_dict(), @@ -293,7 +295,7 @@ class WallRecommendations(Definitions): return recommendations - def find_insulation(self, u_value): + def find_insulation(self, u_value, phase): """ 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 @@ -310,13 +312,15 @@ class WallRecommendations(Definitions): ewi_recommendations = self._find_insulation( u_value=u_value, insulation_materials=pd.DataFrame(self.external_wall_insulation_materials), - non_insulation_materials=self.external_wall_non_insulation_materials + non_insulation_materials=self.external_wall_non_insulation_materials, + phase=phase ) iwi_recommendations = self._find_insulation( u_value=u_value, insulation_materials=pd.DataFrame(self.internal_wall_insulation_materials), - non_insulation_materials=self.internal_wall_non_insulation_materials + non_insulation_materials=self.internal_wall_non_insulation_materials, + phase=phase ) self.recommendations += ewi_recommendations + iwi_recommendations diff --git a/recommendations/WindowsRecommendations.py b/recommendations/WindowsRecommendations.py index b6ecd099..d7404e3b 100644 --- a/recommendations/WindowsRecommendations.py +++ b/recommendations/WindowsRecommendations.py @@ -30,7 +30,7 @@ class WindowsRecommendations: raise ValueError("There should only be one window glazing material") self.glazing_material = self.glazing_material[0] - def recommend(self): + def recommend(self, phase=0): """ This method will recommend the best possible glazing options for a property. @@ -85,6 +85,7 @@ class WindowsRecommendations: self.recommendation = [ { + "phase": phase, "parts": [], "type": "windows_glazing", "description": description,