coupling heating and heating controls recommendations

This commit is contained in:
Khalim Conn-Kowlessar 2024-02-19 19:35:25 +00:00
parent d60918b771
commit be71af909e
4 changed files with 156 additions and 68 deletions

View file

@ -363,7 +363,7 @@ class Property:
"internal_wall_insulation", "external_wall_insulation", "cavity_wall_insulation",
"loft_insulation", "room_roof_insulation", "flat_roof_insulation",
"solid_floor_insulation", "suspended_floor_insulation", "exposed_floor_insulation",
"windows_glazing", "solar_pv", "heating_control",
"windows_glazing", "solar_pv", "heating", "heating_control",
]:
raise NotImplementedError("Implement me")

View file

@ -10,16 +10,20 @@ class HeatingControlRecommender:
self.property = property_instance
self.costs = Costs(self.property)
self.recommendations = []
self.recommendation = []
def recommend(self, heating_description):
# Reset the recommendations
self.recommendation = []
def recommend(self, phase=0):
# This first iteration of the recommender will provide very basic recommendation
# We recommend heating controls based on the main heating system
if self.property.main_heating["clean_description"] == "Room heaters, electric":
self.recommend_room_heaters_electric_controls(phase=phase)
if heating_description in ["Room heaters, electric", "Electric storage heaters, radiators"]:
self.recommend_room_heaters_electric_controls()
return
def recommend_room_heaters_electric_controls(self, phase):
def recommend_room_heaters_electric_controls(self):
"""
If the home has Room heaters, electric, we start by identifying potential heating controls that could
be upgraded, that would provide a practical impact. This will be the least invasive improvement.
@ -57,18 +61,10 @@ class HeatingControlRecommender:
# This upgrade will only take the heating system to average energy efficiency
simulation_config["mainheatc_energy_eff_ending"] = "Good"
self.recommendations.append(
self.recommendation.append(
{
"phase": phase,
"parts": [
# TODO
],
"type": "heating_control",
"description": "Upgrade heating controls to Programmer and Appliance or Smart "
"Thermostats for more precise heating control, and prevention of overheating",
"starting_u_value": None,
"new_u_value": None,
"sap_points": None,
"description": "upgrade heating controls to Programmer and Appliance or Smart Thermostats",
**self.costs.programmer_and_appliance_thermostat(has_programmer=has_programmer),
"simulation_config": simulation_config
}

View file

@ -2,6 +2,7 @@ from recommendations.Costs import Costs
from recommendations.recommendation_utils import check_simulation_difference
from backend.Property import Property
from etl.epc_clean.epc_attributes.MainheatAttributes import MainHeatAttributes
from recommendations.HeatingControlRecommender import HeatingControlRecommender
class HeatingRecommender:
@ -13,10 +14,12 @@ class HeatingRecommender:
self.recommendations = []
def recommend(self, phase=0):
self.recommendations = []
# This first iteration of the recommender will provide very basic recommendation
# We recommend heating controls based on the main heating system
if self.property.main_heating["clean_description"] == "Room heaters, electric":
self.recommend_room_heaters_electric(phase=phase)
self.recommend_room_heaters_electric(phase=phase, heating_controls_only=True)
self.recommend_electric_storage_heaters(phase=phase, heating_controls_only=False)
return
@staticmethod
@ -32,7 +35,128 @@ class HeatingRecommender:
return differences
def recommend_room_heaters_electric(self, phase):
@staticmethod
def combine_heating_and_controls(
controls_recommendations, heating_simulation_config, costs, description, phase, heating_controls_only
):
"""
Given a recommendation for heating controls, and a recommendation for the heating system, we combine the two
into a single recommendation
:param controls_recommendations: The heating controls recommendations
:param heating_simulation_config: The simulation configuration for the heating system
:param costs: The costs of the heating system
:param description: The description of the recommendation
:param phase: The phase of the recommendation
:param heating_controls_only: If True, we will also add a recommendation for heating controls only
:return:
"""
# We produce recommendations with & without heating controls
# We will also produce a recommendation for heating controls only
heating_controls_switch = [True, False] if controls_recommendations else [False]
if not heating_simulation_config:
heating_controls_switch = []
output = []
for controls_switch in heating_controls_switch:
total_costs = costs.copy()
recommendation_simulation_config = heating_simulation_config.copy()
if controls_switch:
# We add the costs of the heating controls, onto each key in the costs dictionary
for key in total_costs:
total_costs[key] += controls_recommendations[0][key]
recommendation_simulation_config = {
**recommendation_simulation_config,
**controls_recommendations[0]["simulation_config"]
}
description = f"{description} and {controls_recommendations[0]['description']}"
recommendation = {
"phase": phase,
"parts": [
# TODO
],
"type": "heating",
"description": description,
"starting_u_value": None,
"new_u_value": None,
"sap_points": None,
**total_costs,
"simulation_config": recommendation_simulation_config
}
output.append(recommendation)
if heating_controls_only and len(controls_recommendations):
# Also add on a recommendation for heating controls only
heating_control_recommendation = controls_recommendations[0].copy()
# Capitalize the first letter of the description
heating_control_recommendation["description"] = (
heating_control_recommendation["description"][0].upper() +
heating_control_recommendation["description"][1:]
)
output.append(
{
"phase": phase,
"starting_u_value": None,
"new_u_value": None,
"sap_points": None,
**heating_control_recommendation
}
)
return output
def recommend_electric_storage_heaters(self, phase, heating_controls_only):
"""
We recommend electric storage heaters as an upgrade to the heating system.
:return:
"""
controls_recommender = HeatingControlRecommender(self.property)
controls_recommender.recommend(heating_description="Room heaters, electric")
if self.property.data["mainheat-energy-eff"] not in ["Poor", "Very Poor"]:
# We do just heating controls
recs = self.combine_heating_and_controls(
controls_recommendations=controls_recommender.recommendation,
heating_simulation_config={},
costs={},
description="",
phase=phase,
heating_controls_only=heating_controls_only
)
return
# Set up artefacts, suitable for the simulation and regardless of controls
heating_ending_config = MainHeatAttributes("Electric storage heaters, radiators").process()
heating_simulation_config = check_simulation_difference(
new_config=heating_ending_config, old_config=self.property.main_heating
)
# This upgrade will only take the heating system to average energy efficiency
heating_simulation_config["mainheatc_energy_eff_ending"] = "Good"
# Upgrade to electric storage heaters
costs = self.costs.electric_storage_heaters(
number_heated_rooms=self.property.data["number-heated-rooms"]
)
description = "Install electric storage heaters"
recommendations = self.combine_heating_and_controls(
controls_recommendations=controls_recommender.recommendation,
heating_simulation_config=heating_simulation_config,
costs=costs,
description=description,
phase=phase,
heating_controls_only=heating_controls_only
)
self.recommendations.extend(recommendations)
def recommend_room_heaters_electric(self, phase, heating_controls_only):
"""
If the home has Room heaters, electric, we start by identifying potential heating controls that could
be upgraded, that would provide a practical impact. This will be the least invasive improvement.
@ -40,49 +164,24 @@ class HeatingRecommender:
We can then consider the heating system itself
:return:
"""
if self.property.data["mainheat-energy-eff"] in ["Poor", "Very Poor"]:
# Re recommend two possible upgrades:
# 1) Installation of more efficient electic room heaters
# 2) Installation of electric storage heaters
if self.property.data["mainheat-energy-eff"] not in ["Poor", "Very Poor"]:
return
room_heater_recommendation = {
"phase": phase,
"parts": [
# TODO
],
"type": "heating",
"description": "Upgrade electric room heaters to more electric radiators",
"starting_u_value": None,
"new_u_value": None,
"sap_points": None,
**self.costs.electric_room_heaters(number_heated_rooms=self.property.data["number-heated-rooms"]),
"simulation_config": {"mainheat_energy_eff_ending": "Average"}
}
controls_recommender = HeatingControlRecommender(self.property)
controls_recommender.recommend(heating_description="Room heaters, electric")
costs = self.costs.electric_room_heaters(
number_heated_rooms=self.property.data["number-heated-rooms"]
)
description = "Upgrade electric room heaters to more electric radiators"
heating_simulation_config = {"mainheat_energy_eff_ending": "Average"}
ending_config = MainHeatAttributes("Electric storage heaters, radiators").process()
simulation_config = check_simulation_difference(
new_config=ending_config, old_config=self.property.main_heating
)
# This upgrade will only take the heating system to average energy efficiency
simulation_config["mainheatc_energy_eff_ending"] = "Good"
recommendations = self.combine_heating_and_controls(
controls_recommender=controls_recommender,
heating_simulation_config=heating_simulation_config,
costs=costs,
description=description,
phase=phase,
heating_controls_only=heating_controls_only
)
electric_storage_heaters_recommendation = {
"phase": phase,
"parts": [
# TODO
],
"type": "heating",
"description": "Install electric storage heaters",
"starting_u_value": None,
"new_u_value": None,
"sap_points": None,
**self.costs.electric_storage_heaters(number_heated_rooms=self.property.data["number-heated-rooms"]),
"simulation_config": simulation_config
}
self.recommendations.extend(
[room_heater_recommendation, electric_storage_heaters_recommendation]
)
# We don't implement any other recommendations right now
return
self.recommendations.extend(recommendations)

View file

@ -10,7 +10,6 @@ from recommendations.LightingRecommendations import LightingRecommendations
from recommendations.SolarPvRecommendations import SolarPvRecommendations
from recommendations.WindowsRecommendations import WindowsRecommendations
from recommendations.HeatingRecommender import HeatingRecommender
from recommendations.HeatingControlRecommender import HeatingControlRecommender
from backend.ml_models.AnnualBillSavings import AnnualBillSavings
@ -43,7 +42,6 @@ class Recommendations:
self.windows_recommender = WindowsRecommendations(property_instance=property_instance, materials=materials)
self.solar_recommender = SolarPvRecommendations(property_instance=property_instance)
self.heating_recommender = HeatingRecommender(property_instance=property_instance)
self.heating_control_recommender = HeatingControlRecommender(property_instance=property_instance)
def recommend(self):
@ -99,11 +97,6 @@ class Recommendations:
property_recommendations.append(self.heating_recommender.recommendations)
phase += 1
self.heating_control_recommender.recommend(phase=phase)
if self.heating_control_recommender.recommendations:
property_recommendations.append(self.heating_control_recommender.recommendations)
phase += 1
self.lighting_recommender.recommend(phase=phase)
if self.lighting_recommender.recommendation:
property_recommendations.append(self.lighting_recommender.recommendation)