From 0eb81b6e7cedfaa91c675e03cc8a90b1240ad086 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Thu, 5 Sep 2024 13:51:13 +0100 Subject: [PATCH] added measures recs into heating --- backend/Property.py | 4 +- recommendations/HeatingRecommender.py | 23 ++-- recommendations/Recommendations.py | 100 +++++++++--------- recommendations/VentilationRecommendations.py | 5 +- 4 files changed, 66 insertions(+), 66 deletions(-) diff --git a/backend/Property.py b/backend/Property.py index 19e5cb2e..3cc8350d 100644 --- a/backend/Property.py +++ b/backend/Property.py @@ -1231,12 +1231,12 @@ class Property: else: raise Exception("Investiage me") - def is_ashp_valid(self, exclusions): + def is_ashp_valid(self, measures): if "air_source_heat_pump" in self.non_invasive_recommendations: return True - if "air_source_heat_pump" in exclusions: + if "air_source_heat_pump" not in measures: return False suitable_property_type = self.data["property-type"] in ["House", "Bungalow"] diff --git a/recommendations/HeatingRecommender.py b/recommendations/HeatingRecommender.py index 78dce329..ac4f3000 100644 --- a/recommendations/HeatingRecommender.py +++ b/recommendations/HeatingRecommender.py @@ -1,6 +1,7 @@ from recommendations.Costs import Costs, BOILER_UPGRADE_SCHEME_ASHP_VALUE from recommendations.recommendation_utils import check_simulation_difference, override_costs from backend.Property import Property +from backend.app.plan.schemas import MEASURE_MAP from etl.epc_clean.epc_attributes.MainheatAttributes import MainHeatAttributes from etl.epc_clean.epc_attributes.HotWaterAttributes import HotWaterAttributes from etl.epc_clean.epc_attributes.MainFuelAttributes import MainFuelAttributes @@ -28,7 +29,7 @@ class HeatingRecommender: self.property.main_heating["clean_description"] in self.ELECTRIC_HEATING_DESCRIPTIONS ) - def is_high_heat_retention_valid(self, ashp_only_heating_recommendation, exclusions): + def is_high_heat_retention_valid(self, ashp_only_heating_recommendation, measures): """ Check conditions if high heat retention storage is valid :return: @@ -43,10 +44,11 @@ class HeatingRecommender: has_electric = self.has_electric_heating_description or electric_heating_assumed return ( - has_electric and (not ashp_only_heating_recommendation) and ("boiler_upgrade" not in exclusions) + has_electric and (not ashp_only_heating_recommendation) and + ("high_heat_retention_storage_heater" in measures) ) - def is_boiler_upgrade_suitable(self, exclusions, ashp_only_heating_recommendation): + def is_boiler_upgrade_suitable(self, measures, ashp_only_heating_recommendation): """ These are the conditions we apply to recommend a boiler installation :return: @@ -84,12 +86,12 @@ class HeatingRecommender: portable_heaters_has_mains ) and (not ashp_only_heating_recommendation) and - ("boiler_upgrade" not in exclusions) + ("boiler_upgrade" in measures) ) return is_valid, has_boiler - def recommend(self, has_cavity_or_loft_recommendations, phase=0, exclusions=None): + def recommend(self, has_cavity_or_loft_recommendations, phase=0, measures=None): """ Produces heating recommendations @@ -97,16 +99,17 @@ class HeatingRecommender: recommendation. If there are cavity or loft recommendations, the property would need to complete those measures before being able to get the boiler upgrade scheme benefits. The messaging in the front end would be to :param phase: indicates the phase of the retrofit programme - :param exclusions: A list of exclusions for the recommendations + :param measures: A list of measures for the recommendations """ + measures = MEASURE_MAP["heating"] if measures is None else measures + # TODO: We could have a system flush recommendation for an existing boiler, where there is no need to replace # the boiler, but instead flushing the system will make it run more efficiently. There is a cost for this # in the Costs class, stored as SYSTEM_FLUSH_COST # TODO: Right now, we don't have recommendations for electric boilers - we should probably have one - exclusions = [] if exclusions is None else exclusions non_invasive_ashp_recommendation = next( (r for r in self.property.non_invasive_recommendations if r["type"] == "air_source_heat_pump"), {"suitable": True} @@ -122,7 +125,7 @@ class HeatingRecommender: # This first iteration of the recommender will provide very basic recommendation # We recommend heating controls based on the main heating system - hhr_valid = self.is_high_heat_retention_valid(ashp_only_heating_recommendation, exclusions) + hhr_valid = self.is_high_heat_retention_valid(ashp_only_heating_recommendation, measures) if hhr_valid: # Recommend high heat retention storage heaters @@ -131,7 +134,7 @@ class HeatingRecommender: self.recommend_hhr_storage_heaters(phase=phase, system_change=True, heating_controls_only=False) gas_boiler_suitable, has_boiler = self.is_boiler_upgrade_suitable( - exclusions=exclusions, ashp_only_heating_recommendation=ashp_only_heating_recommendation + measures=measures, ashp_only_heating_recommendation=ashp_only_heating_recommendation ) if gas_boiler_suitable: @@ -153,7 +156,7 @@ 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 - if self.property.is_ashp_valid(exclusions=exclusions) and non_invasive_ashp_recommendation["suitable"]: + if self.property.is_ashp_valid(measures=measures) and non_invasive_ashp_recommendation["suitable"]: self.recommend_air_source_heat_pump( phase=phase, has_cavity_or_loft_recommendations=has_cavity_or_loft_recommendations, diff --git a/recommendations/Recommendations.py b/recommendations/Recommendations.py index e81e7998..4bcc2a40 100644 --- a/recommendations/Recommendations.py +++ b/recommendations/Recommendations.py @@ -121,8 +121,11 @@ 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 self.wall_recomender.recommendations or self.roof_recommender.recommendations: - self.ventilation_recomender.recommend(measures=measures) + if ( + (self.wall_recomender.recommendations or self.roof_recommender.recommendations) and + ("ventilation" in measures) + ): + self.ventilation_recomender.recommend() if self.ventilation_recomender.recommendation: property_recommendations.append(self.ventilation_recomender.recommendation) @@ -144,57 +147,54 @@ class Recommendations: property_recommendations.append(self.fireplace_recommender.recommendation) phase += 1 - # Heating and Electical systems - if "heating" in measures: + cavity_or_loft_recommendations = [ + r for r in self.wall_recomender.recommendations + self.roof_recommender.recommendations + if r["type"] in ["cavity_wall_insulation", "loft_insulation"] + ] + has_cavity_or_loft_recommendations = len(cavity_or_loft_recommendations) > 0 - cavity_or_loft_recommendations = [ - r for r in self.wall_recomender.recommendations + self.roof_recommender.recommendations - if r["type"] in ["cavity_wall_insulation", "loft_insulation"] - ] - has_cavity_or_loft_recommendations = len(cavity_or_loft_recommendations) > 0 + self.heating_recommender.recommend( + phase=phase, + measures=measures, + has_cavity_or_loft_recommendations=has_cavity_or_loft_recommendations, + ) + if ( + self.heating_recommender.heating_recommendations or + self.heating_recommender.heating_control_recommendations + ): - self.heating_recommender.recommend( - phase=phase, - has_cavity_or_loft_recommendations=has_cavity_or_loft_recommendations, - exclusions=self.exclusions - ) - if ( - self.heating_recommender.heating_recommendations or - self.heating_recommender.heating_control_recommendations - ): - - # We split into first and second phase recommendations - first_phase_recommendations = [ - r for r in ( - self.heating_recommender.heating_recommendations + - self.heating_recommender.heating_control_recommendations - ) - if r["phase"] == phase - ] - second_phase_recommendations = [ - r for r in ( - self.heating_recommender.heating_recommendations + - self.heating_recommender.heating_control_recommendations - ) - if r["phase"] == phase + 1 - ] - - if first_phase_recommendations: - property_recommendations.append(first_phase_recommendations) - - if second_phase_recommendations: - property_recommendations.append(second_phase_recommendations) - - # We check if we have distinct heating and heating controls recommendations - # If so, we increment by 2 (one of the heating system, one for the heating controls) - # otherwise we incremenet by 1 - max_used_phase = max( - [rec["phase"] for rec in - self.heating_recommender.heating_recommendations + - self.heating_recommender.heating_control_recommendations] + # We split into first and second phase recommendations + first_phase_recommendations = [ + r for r in ( + self.heating_recommender.heating_recommendations + + self.heating_recommender.heating_control_recommendations ) - amount_to_increment = max_used_phase - phase + 1 - phase += amount_to_increment + if r["phase"] == phase + ] + second_phase_recommendations = [ + r for r in ( + self.heating_recommender.heating_recommendations + + self.heating_recommender.heating_control_recommendations + ) + if r["phase"] == phase + 1 + ] + + if first_phase_recommendations: + property_recommendations.append(first_phase_recommendations) + + if second_phase_recommendations: + property_recommendations.append(second_phase_recommendations) + + # We check if we have distinct heating and heating controls recommendations + # If so, we increment by 2 (one of the heating system, one for the heating controls) + # otherwise we incremenet by 1 + max_used_phase = max( + [rec["phase"] for rec in + self.heating_recommender.heating_recommendations + + self.heating_recommender.heating_control_recommendations] + ) + amount_to_increment = max_used_phase - phase + 1 + phase += amount_to_increment # Hot water if "hot_water" in measures: diff --git a/recommendations/VentilationRecommendations.py b/recommendations/VentilationRecommendations.py index 4f88b953..1120654a 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, measures=None): + def recommend(self): """ If there is no ventilation, we recommend installing ventilation @@ -37,9 +37,6 @@ 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: