mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
commit
992393d4f3
6 changed files with 151 additions and 41 deletions
|
|
@ -350,8 +350,21 @@ class Property:
|
|||
r for r in property_representative_recommendations
|
||||
if r["phase"] <= phase
|
||||
]
|
||||
epc_transformations = [x["description_simulation"] for x in represenative_recs_to_this_phase]
|
||||
|
||||
|
||||
# TODO: This is placeholder, but it's to handle the case of having both internal and external wall
|
||||
# insulation as options. This will cause the process below to fall over, so we take just
|
||||
# external wall insulation in epc_transformations, if we have both
|
||||
types = [
|
||||
x["type"] for x in represenative_recs_to_this_phase
|
||||
]
|
||||
if "external_wall_insulation" in types and "internal_wall_insulation" in types:
|
||||
epc_transformations = [
|
||||
x["description_simulation"] for x in represenative_recs_to_this_phase if
|
||||
x["type"] != "internal_wall_insulation"
|
||||
]
|
||||
else:
|
||||
epc_transformations = [x["description_simulation"] for x in represenative_recs_to_this_phase]
|
||||
|
||||
# It is possible that we could have two simulations applied to the same descriptions
|
||||
# We extract these out
|
||||
phase_epc_transformation = {}
|
||||
|
|
|
|||
|
|
@ -488,13 +488,6 @@ async def trigger_plan(body: PlanTriggerRequest):
|
|||
"carbon_ending"]
|
||||
)
|
||||
|
||||
from utils.s3 import save_dataframe_to_s3_parquet
|
||||
save_dataframe_to_s3_parquet(
|
||||
bucket_name="retrofit-datalake-dev",
|
||||
file_key="recommendations_scoring_data_11th_july.parquet",
|
||||
df=recommendations_scoring_data
|
||||
)
|
||||
|
||||
model_api = ModelApi(portfolio_id=body.portfolio_id, timestamp=created_at)
|
||||
|
||||
all_predictions = model_api.predictions_template()
|
||||
|
|
@ -510,8 +503,6 @@ async def trigger_plan(body: PlanTriggerRequest):
|
|||
for key, scored in predictions_dict.items():
|
||||
all_predictions[key] = pd.concat([all_predictions[key], scored])
|
||||
|
||||
prediction_df = all_predictions["heating_cost_predictions"]
|
||||
|
||||
# Insert the predictions into the recommendations and run the optimiser
|
||||
# TODO: If a recommendation has a negative impact on SAP, we should remove it - this seems to have become a
|
||||
# possibility with heating system
|
||||
|
|
|
|||
37
etl/sfr/example_retrofit_plan.py
Normal file
37
etl/sfr/example_retrofit_plan.py
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import pandas as pd
|
||||
from utils.s3 import save_csv_to_s3
|
||||
|
||||
PORTFOLIO_ID = 85
|
||||
USER_ID = 8
|
||||
|
||||
|
||||
def app():
|
||||
asset_list = [
|
||||
{
|
||||
"address": "120 Yarningale Road",
|
||||
"postcode": "B14 6NB",
|
||||
"uprn": 100070575194
|
||||
}
|
||||
]
|
||||
|
||||
asset_list = pd.DataFrame(asset_list)
|
||||
|
||||
filename = f"{USER_ID}/{PORTFOLIO_ID}/sample.csv"
|
||||
save_csv_to_s3(
|
||||
dataframe=asset_list,
|
||||
bucket_name="retrofit-plan-inputs-dev",
|
||||
file_name=filename
|
||||
)
|
||||
|
||||
body = {
|
||||
"portfolio_id": str(PORTFOLIO_ID),
|
||||
"housing_type": "Private",
|
||||
"goal": "Increase EPC",
|
||||
"goal_value": "C",
|
||||
"trigger_file_path": filename,
|
||||
"already_installed_file_path": "",
|
||||
"patches_file_path": "",
|
||||
"non_invasive_recommendations_file_path": "",
|
||||
"budget": None,
|
||||
}
|
||||
print(body)
|
||||
|
|
@ -100,9 +100,10 @@ class HeatingControlRecommender:
|
|||
We can then consider the heating system itself
|
||||
:return:
|
||||
"""
|
||||
new_description = "Controls for high heat retention storage heaters"
|
||||
|
||||
# We recommend upgrading to Celect type controls
|
||||
ending_config = MainheatControlAttributes("Controls for high heat retention storage heaters").process()
|
||||
ending_config = MainheatControlAttributes(new_description).process()
|
||||
# We look at what has changed in the ending config, and compare it to the current config
|
||||
simulation_config = check_simulation_difference(
|
||||
new_config=ending_config, old_config=self.property.main_heating_controls
|
||||
|
|
@ -110,11 +111,17 @@ class HeatingControlRecommender:
|
|||
# This upgrade will only take the heating system to average energy efficiency
|
||||
simulation_config["mainheatc_energy_eff_ending"] = "Good"
|
||||
|
||||
description_simulation = {
|
||||
"mainheatcont-description": new_description,
|
||||
"mainheatc-energy-eff": simulation_config["mainheatc_energy_eff_ending"]
|
||||
}
|
||||
|
||||
self.recommendation.append(
|
||||
{
|
||||
"description": "upgrade heating controls to High Heat Retention Storage Heater Controls",
|
||||
**self.costs.celect_type_controls(),
|
||||
"simulation_config": simulation_config
|
||||
"simulation_config": simulation_config,
|
||||
"description_simulation": description_simulation
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -152,7 +159,9 @@ class HeatingControlRecommender:
|
|||
if not can_recommend:
|
||||
return
|
||||
|
||||
ending_config = MainheatControlAttributes("Programmer, room thermostat and TRVS").process()
|
||||
new_controls_description = "Programmer, room thermostat and TRVS"
|
||||
|
||||
ending_config = MainheatControlAttributes(new_controls_description).process()
|
||||
# We use this to determine how we should be updating the config
|
||||
simulation_config = check_simulation_difference(
|
||||
new_config=ending_config, old_config=self.property.main_heating_controls
|
||||
|
|
@ -161,6 +170,13 @@ class HeatingControlRecommender:
|
|||
# If the current system is below good, we make it good
|
||||
if self.property.data["mainheatc-energy-eff"] in ["Poor", "Very Poor", "Average"]:
|
||||
simulation_config["mainheatc_energy_eff_ending"] = "Good"
|
||||
else:
|
||||
simulation_config["mainheatc_energy_eff_ending"] = self.property.data["mainheatc-energy-eff"]
|
||||
|
||||
description_simulation = {
|
||||
"mainheatcont-description": new_controls_description,
|
||||
"mainheatc-energy-eff": simulation_config["mainheatc_energy_eff_ending"]
|
||||
}
|
||||
|
||||
has_programmer = not needs_programmer
|
||||
has_room_thermostat = not needs_room_thermostat
|
||||
|
|
@ -191,10 +207,7 @@ class HeatingControlRecommender:
|
|||
"sap_points": None,
|
||||
"already_installed": already_installed,
|
||||
"simulation_config": simulation_config,
|
||||
"description_simulation": {
|
||||
"mainheatcont-description": "Programmer, room thermostat and TRVS",
|
||||
"mainheatc-energy-eff": "Good"
|
||||
}
|
||||
"description_simulation": description_simulation
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -221,7 +234,9 @@ class HeatingControlRecommender:
|
|||
# No recommendation needed
|
||||
return
|
||||
|
||||
ending_config = MainheatControlAttributes("Time and temperature zone control").process()
|
||||
new_controls_description = "Time and temperature zone control"
|
||||
|
||||
ending_config = MainheatControlAttributes(new_controls_description).process()
|
||||
|
||||
# We use this to determine how we should be updating the config
|
||||
simulation_config = check_simulation_difference(
|
||||
|
|
@ -231,7 +246,13 @@ class HeatingControlRecommender:
|
|||
# If the current system is below very good, we make it very good
|
||||
if self.property.data["mainheatc-energy-eff"] in ["Poor", "Very Poor", "Average", "Good"]:
|
||||
simulation_config["mainheatc_energy_eff_ending"] = "Very Good"
|
||||
else:
|
||||
simulation_config["mainheatc_energy_eff_ending"] = self.property.data["mainheatc-energy-eff"]
|
||||
|
||||
description_simulation = {
|
||||
"mainheatcont-description": new_controls_description,
|
||||
"mainheatc-energy-eff": simulation_config["mainheatc_energy_eff_ending"]
|
||||
}
|
||||
cost_result = self.costs.time_and_temperature_zone_control(
|
||||
number_heated_rooms=int(self.property.data["number-heated-rooms"])
|
||||
)
|
||||
|
|
@ -255,9 +276,6 @@ class HeatingControlRecommender:
|
|||
"sap_points": None,
|
||||
"already_installed": already_installed,
|
||||
"simulation_config": simulation_config,
|
||||
"description_simulation": {
|
||||
"mainheatcont-description": "Time and temperature zone control",
|
||||
"mainheatc-energy-eff": "Very Good"
|
||||
}
|
||||
"description_simulation": description_simulation
|
||||
}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ class HeatingRecommender:
|
|||
# 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
|
||||
|
||||
|
||||
exclusions = [] if exclusions is None else exclusions
|
||||
|
||||
self.heating_recommendations = []
|
||||
|
|
@ -86,7 +86,8 @@ class HeatingRecommender:
|
|||
electic_heating_has_mains = self.has_electric_heating_description and self.property.data["mains-gas-flag"]
|
||||
|
||||
portable_heaters_has_mains = (
|
||||
self.property.main_heating["clean_description"] in ["Portable electric heaters assumed for most rooms"] and
|
||||
self.property.main_heating["clean_description"] in ["Portable electric heaters assumed for most rooms"]
|
||||
and
|
||||
self.property.data["mains-gas-flag"]
|
||||
)
|
||||
|
||||
|
|
@ -238,28 +239,31 @@ class HeatingRecommender:
|
|||
description = description + (f" The cost includes the £"
|
||||
f"{BOILER_UPGRADE_SCHEME_ASHP_VALUE} boiler upgrade scheme grant")
|
||||
|
||||
new_heating_description = "Air source heat pump, radiators, electric"
|
||||
new_hot_water_description = "From main system"
|
||||
simulation_config = {
|
||||
"mainheat_energy_eff_ending": "Good",
|
||||
"hot_water_energy_eff_ending": "Good"
|
||||
}
|
||||
description_simulation = {
|
||||
"mainheat-description": "Air source heat pump, radiators, electric",
|
||||
"mainheat-energy-eff": "Good",
|
||||
"hot-water-energy-eff": "Good",
|
||||
"hotwater-description": "From main system",
|
||||
"mainheat-description": new_heating_description,
|
||||
"mainheat-energy-eff": simulation_config["mainheat_energy_eff_ending"],
|
||||
"hot-water-energy-eff": simulation_config["hot_water_energy_eff_ending"],
|
||||
"hotwater-description": new_hot_water_description,
|
||||
}
|
||||
# Installation of a boiler improves the hot water system so we need to reflect this in
|
||||
# the outcome of the recommendation
|
||||
heating_ending_config = MainHeatAttributes("Air source heat pump, radiators, electric").process()
|
||||
hotwater_ending_config = HotWaterAttributes("From main system").process()
|
||||
heating_ending_config = MainHeatAttributes(new_heating_description).process()
|
||||
hotwater_ending_config = HotWaterAttributes(new_hot_water_description).process()
|
||||
|
||||
# If the property does not currently have electric main fuel, we'll simulate the change
|
||||
fuel_ending_config = {}
|
||||
if self.property.main_fuel["fuel_type"] != "electricity":
|
||||
fuel_ending_config = MainFuelAttributes("electricity (not community)").process()
|
||||
new_fuel_description = "electricity (not community)"
|
||||
fuel_ending_config = MainFuelAttributes(new_fuel_description).process()
|
||||
description_simulation = {
|
||||
**description_simulation,
|
||||
"main-fuel": "electricity (not community)"
|
||||
"main-fuel": new_fuel_description
|
||||
}
|
||||
|
||||
# Check the simulation differences
|
||||
|
|
@ -292,8 +296,7 @@ class HeatingRecommender:
|
|||
|
||||
description_simulation = {
|
||||
**description_simulation,
|
||||
"mainheatcont-description": "time and temperature zone control",
|
||||
"mainheatc-energy-eff": "Very Good"
|
||||
**controls_recommender.recommendation[0]["description_simulation"]
|
||||
}
|
||||
|
||||
ashp_recommendation = {
|
||||
|
|
@ -330,7 +333,14 @@ class HeatingRecommender:
|
|||
return differences
|
||||
|
||||
def combine_heating_and_controls(
|
||||
self, controls_recommendations, heating_simulation_config, costs, description, phase, heating_controls_only,
|
||||
self,
|
||||
controls_recommendations,
|
||||
heating_simulation_config,
|
||||
heating_description_simulation,
|
||||
costs,
|
||||
description,
|
||||
phase,
|
||||
heating_controls_only,
|
||||
system_change
|
||||
):
|
||||
"""
|
||||
|
|
@ -338,6 +348,7 @@ class HeatingRecommender:
|
|||
into a single recommendation
|
||||
:param controls_recommendations: The heating controls recommendations
|
||||
:param heating_simulation_config: The simulation configuration for the heating system
|
||||
:param heating_description_simulation: The simulation configuration for the heating description
|
||||
:param costs: The costs of the heating system
|
||||
:param description: The description of the recommendation
|
||||
:param phase: The phase of the recommendation
|
||||
|
|
@ -361,6 +372,7 @@ class HeatingRecommender:
|
|||
for controls_switch in heating_controls_switch:
|
||||
total_costs = costs.copy()
|
||||
recommendation_simulation_config = heating_simulation_config.copy()
|
||||
recommendation_description_simulation = heating_description_simulation.copy()
|
||||
recommendation_description = description
|
||||
if controls_switch:
|
||||
# We add the costs of the heating controls, onto each key in the costs dictionary
|
||||
|
|
@ -371,6 +383,12 @@ class HeatingRecommender:
|
|||
**recommendation_simulation_config,
|
||||
**controls_recommendations[0]["simulation_config"]
|
||||
}
|
||||
|
||||
recommendation_description_simulation = {
|
||||
**recommendation_description_simulation,
|
||||
**controls_recommendations[0]["description_simulation"]
|
||||
}
|
||||
|
||||
controls_description = controls_recommendations[0]['description']
|
||||
# Make the first letter of the description lowercase
|
||||
controls_description = (
|
||||
|
|
@ -396,7 +414,8 @@ class HeatingRecommender:
|
|||
"sap_points": None,
|
||||
"already_installed": already_installed,
|
||||
**total_costs,
|
||||
"simulation_config": recommendation_simulation_config
|
||||
"simulation_config": recommendation_simulation_config,
|
||||
"description_simulation": recommendation_description_simulation
|
||||
}
|
||||
|
||||
output.append(recommendation)
|
||||
|
|
@ -474,8 +493,10 @@ class HeatingRecommender:
|
|||
# No recommendation needed
|
||||
return
|
||||
|
||||
new_heating_description = "Electric storage heaters, radiators"
|
||||
|
||||
# Set up artefacts, suitable for the simulation and regardless of controls
|
||||
heating_ending_config = MainHeatAttributes("Electric storage heaters, radiators").process()
|
||||
heating_ending_config = MainHeatAttributes(new_heating_description).process()
|
||||
heating_simulation_config = check_simulation_difference(
|
||||
new_config=heating_ending_config, old_config=self.property.main_heating
|
||||
)
|
||||
|
|
@ -497,9 +518,15 @@ class HeatingRecommender:
|
|||
)
|
||||
description = "Install high heat retention electric storage heaters"
|
||||
|
||||
heating_description_simulation = {
|
||||
"mainheat-description": new_heating_description,
|
||||
"mainheat-energy-eff": heating_simulation_config["mainheat_energy_eff_ending"],
|
||||
}
|
||||
|
||||
recommendations = self.combine_heating_and_controls(
|
||||
controls_recommendations=controls_recommender.recommendation,
|
||||
heating_simulation_config=heating_simulation_config,
|
||||
heating_description_simulation=heating_description_simulation,
|
||||
costs=costs,
|
||||
description=description,
|
||||
phase=phase,
|
||||
|
|
@ -580,6 +607,7 @@ class HeatingRecommender:
|
|||
simulation_config = {}
|
||||
boiler_costs = {}
|
||||
boiler_recommendation = {}
|
||||
description_simulation = {}
|
||||
|
||||
has_inefficient_space_heating = self.property.data["mainheat-energy-eff"] in ["Very Poor", "Poor", "Average"]
|
||||
|
||||
|
|
@ -603,12 +631,22 @@ class HeatingRecommender:
|
|||
"mainheat_energy_eff_ending": "Good",
|
||||
"hot_water_energy_eff_ending": "Good"
|
||||
}
|
||||
|
||||
description_simulation = {
|
||||
"mainheat-energy-eff": simulation_config["mainheat_energy_eff_ending"],
|
||||
"hot-water-energy-eff": simulation_config["hot_water_energy_eff_ending"],
|
||||
}
|
||||
|
||||
if system_change:
|
||||
# Installation of a boiler improves the hot water system so we need to reflect this in
|
||||
# the outcome of the recommendation
|
||||
heating_ending_config = MainHeatAttributes("Boiler and radiators, mains gas").process()
|
||||
hotwater_ending_config = HotWaterAttributes("From main system").process()
|
||||
fuel_ending_config = MainFuelAttributes("mains gas (not community)").process()
|
||||
new_heating_description = "Boiler and radiators, mains gas"
|
||||
new_hotwater_description = "From main system"
|
||||
new_fuel_description = "mains gas (not community)"
|
||||
|
||||
heating_ending_config = MainHeatAttributes(new_heating_description).process()
|
||||
hotwater_ending_config = HotWaterAttributes(new_hotwater_description).process()
|
||||
fuel_ending_config = MainFuelAttributes(new_fuel_description).process()
|
||||
|
||||
heating_simulation_config = check_simulation_difference(
|
||||
new_config=heating_ending_config, old_config=self.property.main_heating
|
||||
|
|
@ -627,6 +665,13 @@ class HeatingRecommender:
|
|||
**fuel_simulation_config,
|
||||
}
|
||||
|
||||
description_simulation = {
|
||||
**description_simulation,
|
||||
"mainheat-description": new_heating_description,
|
||||
"hotwater-description": new_hotwater_description,
|
||||
"main-fuel": new_fuel_description
|
||||
}
|
||||
|
||||
boiler_costs = self.costs.boiler(
|
||||
size=f"{boiler_size}kw",
|
||||
exising_room_heaters=exising_room_heaters,
|
||||
|
|
@ -652,6 +697,7 @@ class HeatingRecommender:
|
|||
"sap_points": None,
|
||||
"already_installed": already_installed,
|
||||
"simulation_config": simulation_config,
|
||||
"description_simulation": description_simulation,
|
||||
**boiler_costs
|
||||
}
|
||||
|
||||
|
|
@ -675,6 +721,7 @@ class HeatingRecommender:
|
|||
combined_recommendation = self.combine_heating_and_controls(
|
||||
controls_recommendations=[controls_recommendation],
|
||||
heating_simulation_config=simulation_config,
|
||||
heating_description_simulation=description_simulation,
|
||||
costs=boiler_costs,
|
||||
description=boiler_recommendation["description"],
|
||||
phase=recommendation_phase,
|
||||
|
|
|
|||
|
|
@ -524,6 +524,10 @@ class WallRecommendations(Definitions):
|
|||
"already_installed": already_installed,
|
||||
"sap_points": None,
|
||||
"simulation_config": simulation_config,
|
||||
"description_simulation": {
|
||||
"walls-description": new_description,
|
||||
"walls-energy-eff": simulation_config["walls_energy_eff_ending"]
|
||||
},
|
||||
**cost_result
|
||||
}
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue