mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Added in second part of recommendation impact calculations
This commit is contained in:
parent
af66744979
commit
3bdc4db92a
4 changed files with 226 additions and 35 deletions
|
|
@ -380,6 +380,7 @@ async def trigger_plan(body: PlanTriggerRequest):
|
|||
target_rating=body.goal_value,
|
||||
current_consumption=p.current_adjusted_energy
|
||||
),
|
||||
"property_id": p.id
|
||||
} for p in input_properties if p.building_id is not None
|
||||
]
|
||||
if building_ids:
|
||||
|
|
@ -419,7 +420,13 @@ async def trigger_plan(body: PlanTriggerRequest):
|
|||
# Insert this into the properties that have this building id
|
||||
for p in input_properties:
|
||||
if p.building_id == building_id:
|
||||
p.set_solar_panel_configuration(solar_panel_configuration[building_id])
|
||||
unit_solar_panel_configuration = solar_panel_configuration[building_id].copy()
|
||||
|
||||
unit_solar_panel_configuration["unit_share_of_energy"] = (
|
||||
[x for x in building_ids if x["property_id"] == p.id][0]["energy_consumption"] /
|
||||
energy_consumption
|
||||
)
|
||||
p.set_solar_panel_configuration(unit_solar_panel_configuration)
|
||||
|
||||
else:
|
||||
# Model the solar potential at the property level
|
||||
|
|
|
|||
|
|
@ -28,8 +28,10 @@ class AnnualBillSavings:
|
|||
# https://www.ofgem.gov.uk/energy-price-cap
|
||||
ELECTRICITY_PRICE_CAP = 0.2236
|
||||
GAS_PRICE_CAP = 0.0548
|
||||
# This is the most recent export payment figure, at 12p per kwh
|
||||
ELECTRICITY_EXPORT_PAYMENT = 0.12
|
||||
# This is the most recent export payment figure, at 9.28p/kWh
|
||||
# Smart export guarantee rates can be found here:
|
||||
# https://www.sunsave.energy/solar-panels-advice/exporting-to-the-grid/best-seg-rates
|
||||
ELECTRICITY_EXPORT_PAYMENT = 0.0928
|
||||
|
||||
# This is a weighted mean of the price caps, using the consumption figures above as weights
|
||||
PRICE_FACTOR = 0.09549999999999999
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ from recommendations.HeatingRecommender import HeatingRecommender
|
|||
from recommendations.HotwaterRecommendations import HotwaterRecommendations
|
||||
from recommendations.SecondaryHeating import SecondaryHeating
|
||||
from backend.ml_models.AnnualBillSavings import AnnualBillSavings
|
||||
from backend.apis.GoogleSolarApi import GoogleSolarApi
|
||||
|
||||
|
||||
class Recommendations:
|
||||
|
|
@ -374,6 +375,8 @@ class Recommendations:
|
|||
# # TODO: We should determine if the home is gas & electricity or just electricity
|
||||
# expected_energy_bill = AnnualBillSavings.calculate_annual_bill(expected_adjusted_energy)
|
||||
|
||||
phase_lighting_costs = {}
|
||||
phase_kwh_figures = {}
|
||||
for recommendations_by_type in property_recommendations:
|
||||
for rec in recommendations_by_type:
|
||||
|
||||
|
|
@ -422,23 +425,52 @@ class Recommendations:
|
|||
float(property_instance.data["energy-consumption-current"]) - new_heat_demand
|
||||
)
|
||||
|
||||
if rec["type"] == "lighting":
|
||||
new_heating_cost = property_instance.energy_cost_estimates["adjusted"]["heating"]
|
||||
new_hot_water_cost = property_instance.energy_cost_estimates["adjusted"]["hot_water"]
|
||||
new_lighting_cost = min(
|
||||
new_lighting_cost, property_instance.energy_cost_estimates["adjusted"]["lighting"]
|
||||
)
|
||||
scoring_heating_cost = property_instance.energy_cost_estimates["unadjusted"]["heating"]
|
||||
scoring_hot_water_cost = property_instance.energy_cost_estimates["unadjusted"]["hot_water"]
|
||||
scoring_lighting_cost = min(
|
||||
property_instance.energy_cost_estimates["unadjusted"]["lighting"],
|
||||
new_lighting_cost_unadjusted
|
||||
)
|
||||
else:
|
||||
new_heating_cost = min(
|
||||
new_heating_cost, property_instance.energy_cost_estimates["adjusted"]["heating"]
|
||||
)
|
||||
new_hot_water_cost = min(
|
||||
new_hot_water_cost, property_instance.energy_cost_estimates["adjusted"]["hot_water"]
|
||||
)
|
||||
new_lighting_cost = property_instance.energy_cost_estimates["adjusted"]["lighting"]
|
||||
|
||||
scoring_heating_cost = min(
|
||||
property_instance.energy_cost_estimates["unadjusted"]["heating"],
|
||||
new_heating_cost_unadjusted
|
||||
)
|
||||
scoring_hot_water_cost = min(
|
||||
property_instance.energy_cost_estimates["unadjusted"]["hot_water"],
|
||||
new_hot_water_cost_unadjusted
|
||||
)
|
||||
scoring_lighting_cost = property_instance.energy_cost_estimates["unadjusted"]["lighting"]
|
||||
|
||||
predicted_heating_cost_reduction = (
|
||||
float(property_instance.energy_cost_estimates["adjusted"]["heating"]) - new_heating_cost
|
||||
property_instance.energy_cost_estimates["adjusted"]["heating"] - new_heating_cost
|
||||
)
|
||||
predicted_hot_water_cost_reduction = (
|
||||
float(property_instance.energy_cost_estimates["adjusted"]["hot_water"]) - new_hot_water_cost
|
||||
)
|
||||
predicted_heating_cost_reduction = (
|
||||
0 if predicted_heating_cost_reduction < 0 else predicted_heating_cost_reduction
|
||||
)
|
||||
predicted_hot_water_cost_reduction = (
|
||||
0 if predicted_hot_water_cost_reduction < 0 else predicted_hot_water_cost_reduction
|
||||
property_instance.energy_cost_estimates["adjusted"]["hot_water"] - new_hot_water_cost
|
||||
)
|
||||
|
||||
# Only lighting recommendations can have an impact here
|
||||
predicted_lighting_cost_reduction = 0 if rec["type"] != "lighting" else (
|
||||
float(property_instance.energy_cost_estimates["adjusted"]["lighting"]) - new_lighting_cost
|
||||
property_instance.energy_cost_estimates["adjusted"]["lighting"] - new_lighting_cost
|
||||
)
|
||||
# We store this value for later
|
||||
phase_lighting_costs[rec["phase"]] = {
|
||||
"adjusted": new_lighting_cost,
|
||||
"unadjusted": scoring_lighting_cost
|
||||
}
|
||||
|
||||
# This is the total bill savings for the recommendation
|
||||
if rec["type"] == "solar_pv":
|
||||
|
|
@ -456,17 +488,6 @@ class Recommendations:
|
|||
)
|
||||
|
||||
# We now predict the kwh savings using the xgb model
|
||||
scoring_heating_cost = min(
|
||||
property_instance.energy_cost_estimates["unadjusted"]["heating"], new_heating_cost_unadjusted
|
||||
)
|
||||
scoring_hot_water_cost = min(
|
||||
property_instance.energy_cost_estimates["unadjusted"]["hot_water"],
|
||||
new_hot_water_cost_unadjusted
|
||||
)
|
||||
scoring_lighting_cost = min(
|
||||
property_instance.energy_cost_estimates["unadjusted"]["lighting"], new_lighting_cost_unadjusted
|
||||
) if rec["type"] == "lighting" \
|
||||
else property_instance.energy_cost_estimates["unadjusted"]["lighting"]
|
||||
|
||||
simulation_epc = property_instance.simulation_epcs[rec["phase"]].copy()
|
||||
# The current heating, hot water and energy kwh should be based on the new, unadjusted
|
||||
|
|
@ -513,6 +534,17 @@ class Recommendations:
|
|||
|
||||
kwh_reduction = heating_kwh_reduction + hot_water_kwh_reduction + lighting_kwh_reduction
|
||||
|
||||
phase_kwh_figures[rec["phase"]] = {
|
||||
"adjusted": {
|
||||
"heating": new_heating_kwh_adjusted,
|
||||
"hot_water": new_hot_water_kwh_adjusted
|
||||
},
|
||||
"unadjusted": {
|
||||
"heating": new_heating_kwh,
|
||||
"hot_water": new_hot_water_kwh
|
||||
}
|
||||
}
|
||||
|
||||
else:
|
||||
previous_phase = rec["phase"] - 1
|
||||
predicted_sap_points = (
|
||||
|
|
@ -527,30 +559,177 @@ class Recommendations:
|
|||
new_heat_demand
|
||||
)
|
||||
|
||||
if rec["type"] == "lighting":
|
||||
# If we have a lighting recommendation, the heating, hot water and lighting costs will
|
||||
# be from the previous phase - nothing will change
|
||||
new_heating_cost = heating_cost_phase_impact[
|
||||
heating_cost_phase_impact["phase"] == previous_phase
|
||||
]["adjusted_cost"].values[0]
|
||||
new_hot_water_cost = hot_water_cost_phase_impact[
|
||||
hot_water_cost_phase_impact["phase"] == previous_phase
|
||||
]["adjusted_cost"].values[0]
|
||||
|
||||
new_lighting_cost = min(
|
||||
new_lighting_cost, phase_lighting_costs[previous_phase]["adjusted"]
|
||||
)
|
||||
# We also use the unadjusted costs for the scoring from the previous phase
|
||||
scoring_heating_cost = heating_cost_phase_impact[
|
||||
heating_cost_phase_impact["phase"] == previous_phase
|
||||
]["predictions"].values[0]
|
||||
scoring_hot_water_cost = hot_water_cost_phase_impact[
|
||||
hot_water_cost_phase_impact["phase"] == previous_phase
|
||||
]["predictions"].values[0]
|
||||
scoring_lighting_cost = min(
|
||||
new_lighting_cost_unadjusted,
|
||||
phase_lighting_costs[previous_phase]["unadjusted"]
|
||||
)
|
||||
else:
|
||||
# Whereas for other recommendations, we use the new costs
|
||||
new_heating_cost = min(
|
||||
new_heating_cost,
|
||||
heating_cost_phase_impact[
|
||||
heating_cost_phase_impact["phase"] == previous_phase
|
||||
]["adjusted_cost"].values[0]
|
||||
)
|
||||
new_hot_water_cost = min(
|
||||
new_hot_water_cost,
|
||||
hot_water_cost_phase_impact[
|
||||
hot_water_cost_phase_impact["phase"] == previous_phase
|
||||
]["adjusted_cost"].values[0]
|
||||
)
|
||||
new_lighting_cost = phase_lighting_costs[previous_phase]["adjusted"]
|
||||
|
||||
scoring_heating_cost = min(
|
||||
new_heating_cost_unadjusted,
|
||||
heating_cost_phase_impact[
|
||||
heating_cost_phase_impact["phase"] == previous_phase
|
||||
]["predictions"].values[0]
|
||||
)
|
||||
scoring_hot_water_cost = min(
|
||||
new_hot_water_cost_unadjusted,
|
||||
hot_water_cost_phase_impact[
|
||||
hot_water_cost_phase_impact["phase"] == previous_phase
|
||||
]["predictions"].values[0]
|
||||
)
|
||||
scoring_lighting_cost = phase_lighting_costs[previous_phase]["unadjusted"]
|
||||
|
||||
# We now estimate the adjusted cost savings for the recommendation
|
||||
predicted_heating_cost_reduction = (
|
||||
heating_cost_phase_impact[heating_cost_phase_impact["phase"] == previous_phase][
|
||||
"adjusted_cost"
|
||||
].values[0] - new_heating_cost
|
||||
)
|
||||
predicted_heating_cost_reduction = (
|
||||
0 if predicted_heating_cost_reduction < 0 else predicted_heating_cost_reduction
|
||||
)
|
||||
|
||||
predicted_hot_water_cost_reduction = (
|
||||
hot_water_cost_phase_impact[hot_water_cost_phase_impact["phase"] == previous_phase][
|
||||
"adjusted_cost"
|
||||
].values[0] - new_hot_water_cost
|
||||
)
|
||||
predicted_hot_water_cost_reduction = (
|
||||
0 if predicted_hot_water_cost_reduction < 0 else predicted_hot_water_cost_reduction
|
||||
)
|
||||
|
||||
# Only lighting recommendations can have an impact here
|
||||
predicted_lighting_cost_reduction = 0 if rec["type"] != "lighting" else (
|
||||
lighting_cost_phase_impact[lighting_cost_phase_impact["phase"] == previous_phase][
|
||||
"adjusted_cost"
|
||||
].values[0] - new_lighting_cost
|
||||
predicted_lighting_cost_reduction = (
|
||||
phase_lighting_costs[previous_phase]["adjusted"] - new_lighting_cost
|
||||
)
|
||||
|
||||
# We now predict the kwh savings using the xgb model - this is based on
|
||||
# the new costs at this phase
|
||||
|
||||
simulation_epc = property_instance.simulation_epcs[rec["phase"]].copy()
|
||||
# The current heating, hot water and energy kwh should be based on the new, unadjusted
|
||||
# costs for lighting, heating, hot water
|
||||
simulation_epc["heating-cost-current"] = int(scoring_heating_cost)
|
||||
simulation_epc["hot-water-cost-current"] = int(scoring_hot_water_cost)
|
||||
simulation_epc["lighting-cost-current"] = int(scoring_lighting_cost)
|
||||
# We predict with the energy consumption model
|
||||
scoring_df = pd.DataFrame([simulation_epc])
|
||||
# Change columns from underscores to hyphens
|
||||
scoring_df.columns = [
|
||||
x.lower().replace("_", "-") for x in scoring_df.columns
|
||||
]
|
||||
for col in ["heating_kwh", "hot_water_kwh"]:
|
||||
scoring_df[col] = None
|
||||
|
||||
energy_consumption_client.data = None
|
||||
new_heating_kwh = energy_consumption_client.score_new_data(
|
||||
new_data=scoring_df, target="heating_kwh"
|
||||
)[0]
|
||||
|
||||
new_hot_water_kwh = energy_consumption_client.score_new_data(
|
||||
new_data=scoring_df, target="hot_water_kwh"
|
||||
)[0]
|
||||
|
||||
# Adjust these figures
|
||||
new_heating_kwh_adjusted = AnnualBillSavings.adjust_energy_to_metered(
|
||||
new_heating_kwh, current_epc_rating=property_instance.data["current-energy-rating"]
|
||||
)
|
||||
new_hot_water_kwh_adjusted = AnnualBillSavings.adjust_energy_to_metered(
|
||||
new_hot_water_kwh, current_epc_rating=property_instance.data["current-energy-rating"]
|
||||
)
|
||||
|
||||
heating_kwh_reduction = 0 if predicted_heating_cost_reduction == 0 else (
|
||||
phase_kwh_figures[previous_phase]["adjusted"]["heating"] - new_heating_kwh_adjusted
|
||||
)
|
||||
|
||||
hot_water_kwh_reduction = 0 if predicted_hot_water_cost_reduction == 0 else (
|
||||
phase_kwh_figures[previous_phase]["adjusted"]["hot_water"] - new_hot_water_kwh_adjusted
|
||||
)
|
||||
|
||||
lighting_kwh_reduction = predicted_lighting_cost_reduction / AnnualBillSavings.ELECTRICITY_PRICE_CAP
|
||||
|
||||
# This is the total bill savings for the recommendation
|
||||
|
||||
predicted_appliances_cost_reduction = 0
|
||||
predicted_appliances_kwh_reduction = 0
|
||||
if rec["type"] == "solar_pv":
|
||||
# Calulate the amount of energy the solar panel array will generate for this unit
|
||||
unit_energy_consumption = (
|
||||
rec["initial_ac_kwh_per_year"] *
|
||||
property_instance.solar_panel_configuration["unit_share_of_energy"]
|
||||
)
|
||||
|
||||
unit_energy_utilised = unit_energy_consumption * GoogleSolarApi.SOLAR_CONSUMPTION_PROPORTION
|
||||
unit_energy_exported = unit_energy_consumption - unit_energy_utilised
|
||||
unit_energy_exported_value = unit_energy_exported * AnnualBillSavings.ELECTRICITY_EXPORT_PAYMENT
|
||||
|
||||
# We assume that 50% of the energy generated will be used by the property without a battery
|
||||
# to be conservative
|
||||
|
||||
# of the energy utilised, some of it is used by heating, hot water and lighting so we
|
||||
# remove that from the total
|
||||
unit_energy_utilised -= (
|
||||
heating_kwh_reduction + hot_water_kwh_reduction + lighting_kwh_reduction
|
||||
)
|
||||
unit_energy_utilised = 0 if unit_energy_utilised < 0 else unit_energy_utilised
|
||||
|
||||
# This is how much energy the appliances will use after install
|
||||
post_install_appliance_kwh = (
|
||||
property_instance.energy_consumption_estimates["adjusted"]["appliances"] -
|
||||
unit_energy_utilised
|
||||
)
|
||||
post_install_appliance_kwh = (
|
||||
0 if post_install_appliance_kwh < 0 else post_install_appliance_kwh
|
||||
)
|
||||
|
||||
predicted_appliances_kwh_reduction = (
|
||||
property_instance.energy_consumption_estimates["adjusted"]["appliances"] -
|
||||
post_install_appliance_kwh
|
||||
)
|
||||
|
||||
predicted_appliances_cost_reduction = unit_energy_exported_value + (
|
||||
predicted_appliances_kwh_reduction * AnnualBillSavings.ELECTRICITY_PRICE_CAP
|
||||
)
|
||||
|
||||
# We now calculate the predicted_bill_savings
|
||||
predicted_bill_savings = (
|
||||
predicted_heating_cost_reduction + predicted_hot_water_cost_reduction +
|
||||
predicted_lighting_cost_reduction + predicted_appliances_cost_reduction
|
||||
)
|
||||
|
||||
kwh_reduction = (
|
||||
heating_kwh_reduction +
|
||||
hot_water_kwh_reduction +
|
||||
lighting_kwh_reduction +
|
||||
predicted_appliances_kwh_reduction
|
||||
)
|
||||
|
||||
if rec["type"] == "low_energy_lighting":
|
||||
|
|
|
|||
|
|
@ -113,13 +113,15 @@ class SolarPvRecommendations:
|
|||
|
||||
for rank, recommendation_config in best_configurations.iterrows():
|
||||
roof_coverage_percent = round(recommendation_config["panneled_roof_area"] / total_roof_area * 100)
|
||||
# Spread the cost to the individual units
|
||||
# Spread the cost to the individual units - adding a 20% contingency
|
||||
total_cost = recommendation_config["total_cost"] / n_units
|
||||
kw = np.floor(recommendation_config["array_warrage"] / 100) / 10
|
||||
|
||||
description = (f"Install a {kw} kilowatt-peak (kWp) solar photovoltaic (PV) panel system on the roof "
|
||||
"of the building")
|
||||
|
||||
initial_ac_kwh_per_year = recommendation_config["initial_ac_kwh_per_year"]
|
||||
|
||||
self.recommendation.append(
|
||||
{
|
||||
"phase": phase,
|
||||
|
|
@ -135,6 +137,7 @@ class SolarPvRecommendations:
|
|||
# back up here
|
||||
"photo_supply": roof_coverage_percent,
|
||||
"has_battery": False,
|
||||
"initial_ac_kwh_per_year": initial_ac_kwh_per_year,
|
||||
"description_simulation": {"photo-supply": roof_coverage_percent},
|
||||
"rank": rank # Rank is used to get the representative recommendation - rank 0 will be chosen
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue