mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
184 lines
8.3 KiB
Python
184 lines
8.3 KiB
Python
import pandas as pd
|
|
|
|
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:
|
|
|
|
def __init__(self, property_instance: Property):
|
|
self.property = property_instance
|
|
self.costs = Costs(self.property)
|
|
|
|
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"] in [
|
|
"Room heaters, electric", "Electric storage heaters", "Electric storage heaters, radiators"
|
|
]:
|
|
# Recommend high heat retention storage heaters
|
|
self.recommend_electric_storage_heaters(phase=phase, system_change=True, heating_controls_only=False)
|
|
return
|
|
|
|
@staticmethod
|
|
def check_simulation_difference(old_config, new_config):
|
|
"""
|
|
Given two dictionaries, that describe the heating control configurations, this method will compare the two
|
|
and pick out the differences. These differences will be things that have been added and things that have been
|
|
removed. This will be used to determine how we should be updating the configuration in the simulation
|
|
:return:
|
|
"""
|
|
|
|
differences = {key + "_ending": new_config[key] for key in new_config if old_config[key] != new_config[key]}
|
|
|
|
return differences
|
|
|
|
@staticmethod
|
|
def combine_heating_and_controls(
|
|
controls_recommendations, heating_simulation_config, costs, description, phase, heating_controls_only,
|
|
system_change
|
|
):
|
|
"""
|
|
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
|
|
:param system_change: Indicates if we are recommending a different type of heating system, compared to the
|
|
current system. If we have a system change and we have a heat control recommendation, we only recommend
|
|
both heating and controls together
|
|
: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 = []
|
|
|
|
if system_change and len(controls_recommendations):
|
|
heating_controls_switch = [True]
|
|
|
|
output = []
|
|
for controls_switch in heating_controls_switch:
|
|
total_costs = costs.copy()
|
|
recommendation_simulation_config = heating_simulation_config.copy()
|
|
recommendation_description = description
|
|
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"]
|
|
}
|
|
|
|
recommendation_description = f"{description} and {controls_recommendations[0]['description']}"
|
|
|
|
recommendation = {
|
|
"phase": phase,
|
|
"parts": [
|
|
# TODO
|
|
],
|
|
"type": "heating",
|
|
"description": recommendation_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,
|
|
"parts": [
|
|
# TODO
|
|
],
|
|
"type": "heating",
|
|
"starting_u_value": None,
|
|
"new_u_value": None,
|
|
"sap_points": None,
|
|
**heating_control_recommendation
|
|
}
|
|
)
|
|
|
|
return output
|
|
|
|
def recommend_electric_storage_heaters(self, phase, system_change, heating_controls_only):
|
|
"""
|
|
We recommend electric storage heaters as an upgrade to the heating system.
|
|
We will recommend upgrading to a high heat retention storage system, if the current system is not already
|
|
high heat retention storage
|
|
|
|
:param phase: The phase of the recommendation
|
|
:param system_change: Indicates if we are recommending a different type of heating system, compared to the
|
|
current system
|
|
:param heating_controls_only: Indicates if we should include a recommendation for just heating controls
|
|
:return:
|
|
"""
|
|
|
|
controls_recommender = HeatingControlRecommender(self.property)
|
|
# The heating controls we're recommending for are based on the recommended heating system
|
|
high_heat_retention_contols_desc = "Controls for high heat retention storage heaters"
|
|
# We only recommend Celect-type controls if the current heating system is not Celect-type controls
|
|
if self.property.main_heating_controls["clean_description"] != high_heat_retention_contols_desc:
|
|
controls_recommender.recommend(heating_description="Electric storage heaters, radiators")
|
|
|
|
# Conditions for not needing this recommendation
|
|
already_installed_hh_retention = (
|
|
"Electric storage heaters" in self.property.main_heating["clean_description"] and
|
|
self.property.main_heating_controls["clean_description"].lower() == high_heat_retention_contols_desc.lower()
|
|
)
|
|
|
|
# Conditions for not recommending electric storage heaters
|
|
if already_installed_hh_retention:
|
|
# No recommendation needed
|
|
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["mainheat_energy_eff_ending"] = "Average"
|
|
|
|
# Upgrade to electric storage heaters
|
|
costs = self.costs.high_heat_electric_storage_heaters(
|
|
number_heated_rooms=self.property.data["number-heated-rooms"]
|
|
)
|
|
description = "Install high heat retention 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,
|
|
system_change=system_change
|
|
)
|
|
|
|
self.recommendations.extend(recommendations)
|