Merge pull request #325 from Hestia-Homes/aecom

Aecom
This commit is contained in:
KhalimCK 2024-07-24 16:23:29 +01:00 committed by GitHub
commit 992393d4f3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 151 additions and 41 deletions

View file

@ -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 = {}

View file

@ -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

View 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)

View file

@ -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
}
)

View file

@ -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,

View file

@ -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
}
)