mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
implemented recommendation level kwh and cost savings
This commit is contained in:
parent
a0eabd5f09
commit
2efb2a4f3e
2 changed files with 160 additions and 22 deletions
|
|
@ -183,6 +183,7 @@ class Property:
|
|||
|
||||
self.recommendations_scoring_data = []
|
||||
self.simulation_epcs = {}
|
||||
self.updated_simulation_epcs = []
|
||||
|
||||
# This additional condition data should change how we pass kwargs to this. We should no longer need to pass
|
||||
# kwargs to this class, but instead, we should pass the energy assessment condition data
|
||||
|
|
@ -454,6 +455,9 @@ class Property:
|
|||
)
|
||||
updated_simulation_epcs.append(sim_epc)
|
||||
|
||||
# Now we havet this data inthe
|
||||
self.updated_simulation_epcs = updated_simulation_epcs
|
||||
|
||||
return updated_simulation_epcs
|
||||
|
||||
@staticmethod
|
||||
|
|
|
|||
|
|
@ -671,29 +671,14 @@ async def trigger_plan(body: PlanTriggerRequest):
|
|||
|
||||
# We use the impact_summary to update the simulation_epcs with the new SAP, heat demand, carbon, cost etc
|
||||
# at each phase
|
||||
property_scoring_epcs = property_instance.update_simulation_epcs(impact_summary)
|
||||
scoring_epcs.extend(property_scoring_epcs)
|
||||
property_instance.update_simulation_epcs(impact_summary)
|
||||
scoring_epcs.extend(property_instance.updated_simulation_epcs)
|
||||
recommendations[property_id] = recommendations_with_impact
|
||||
|
||||
# We call the API with the scoring epcs
|
||||
scoring_epcs = pd.DataFrame(scoring_epcs)
|
||||
scoring_epcs = kwh_client.transform(data=scoring_epcs, cleaned=cleaned)
|
||||
|
||||
# There should be no difference between index 9 and index 8, apart from photo-supply (other that sap, etc)
|
||||
a = scoring_epcs[scoring_epcs.index == 6]
|
||||
b = scoring_epcs[scoring_epcs.index == 11]
|
||||
difference = []
|
||||
for col in a.columns:
|
||||
if a[col].values[0] != b[col].values[0]:
|
||||
difference.append(
|
||||
{
|
||||
"col": col,
|
||||
"without_solar": a[col].values[0],
|
||||
"with_solar": b[col].values[0]
|
||||
}
|
||||
)
|
||||
difference = pd.DataFrame(difference)
|
||||
|
||||
kwh_simulation_predictions = model_api.paginated_predictions(
|
||||
data=scoring_epcs,
|
||||
bucket=get_settings().DATA_BUCKET,
|
||||
|
|
@ -715,16 +700,42 @@ async def trigger_plan(body: PlanTriggerRequest):
|
|||
how="inner",
|
||||
on="id",
|
||||
suffixes=("_heating", "_hotwater")
|
||||
).reset_index(drop=True)
|
||||
|
||||
# We adjust this table with the kwh estimates for low energy lighting kwh values, and solar kwh estimates
|
||||
led_recommendation = pd.DataFrame([
|
||||
{
|
||||
"phase": r["phase"],
|
||||
"recommendation_id": r["recommendation_id"],
|
||||
"lighting_kwh_savings": r["kwh_savings"] * GoogleSolarApi.SOLAR_CONSUMPTION_PROPORTION,
|
||||
} for recs in property_recommendations for r in recs if r["type"] == "low_energy_lighting"
|
||||
], columns=["phase", "recommendation_id", "lighting_kwh_savings"])
|
||||
solar_recommendations = pd.DataFrame([
|
||||
{
|
||||
"phase": r["phase"],
|
||||
"recommendation_id": r["recommendation_id"],
|
||||
"solar_kwh_savings": r["initial_ac_kwh_per_year"] * GoogleSolarApi.SOLAR_CONSUMPTION_PROPORTION,
|
||||
} for recs in property_recommendations for r in recs if r["type"] == "solar_pv"
|
||||
], columns=["phase", "recommendation_id", "solar_kwh_savings"])
|
||||
|
||||
# merge them on
|
||||
kwh_impact_table = kwh_impact_table.merge(
|
||||
led_recommendation, how="left", on=["phase", "recommendation_id"]
|
||||
).merge(
|
||||
solar_recommendations, how="left", on=["phase", "recommendation_id"]
|
||||
)
|
||||
|
||||
property_kwh = property_instance.energy_consumption_estimates["unadjusted"]
|
||||
|
||||
starting_dummy_id_value = -9999
|
||||
kwh_impact_table = pd.concat(
|
||||
[
|
||||
pd.DataFrame(
|
||||
[
|
||||
{
|
||||
"id": None,
|
||||
"id": starting_dummy_id_value,
|
||||
"phase": starting_dummy_id_value,
|
||||
"recommendation_id": starting_dummy_id_value,
|
||||
"predictions_heating": property_kwh["heating"],
|
||||
"predictions_hotwater": property_kwh["hot_water"],
|
||||
}
|
||||
|
|
@ -732,7 +743,19 @@ async def trigger_plan(body: PlanTriggerRequest):
|
|||
),
|
||||
kwh_impact_table
|
||||
]
|
||||
)
|
||||
).sort_values(["phase", "recommendation_id"], ascending=True).reset_index(drop=True)
|
||||
|
||||
for i in range(0, len(kwh_impact_table)):
|
||||
current_phase = kwh_impact_table.loc[i, 'phase']
|
||||
previous_phase_id = (current_phase - 1) if (current_phase > 0) else -9999
|
||||
previous_phase = kwh_impact_table[kwh_impact_table['phase'] == previous_phase_id]
|
||||
|
||||
if not previous_phase.empty:
|
||||
for col in ["predictions_heating", "predictions_hotwater"]:
|
||||
if kwh_impact_table.loc[i, col] > previous_phase[col].max():
|
||||
kwh_impact_table.loc[i, col] = previous_phase[col].max()
|
||||
|
||||
from backend.ml_models.AnnualBillSavings import AnnualBillSavings
|
||||
# We adjust the predictions with the UCL model
|
||||
for k in ["heating", "hotwater"]:
|
||||
kwh_impact_table[f"adjusted_{k}"] = kwh_impact_table[f"predictions_{k}"].apply(
|
||||
|
|
@ -741,13 +764,124 @@ async def trigger_plan(body: PlanTriggerRequest):
|
|||
)
|
||||
)
|
||||
|
||||
kwh_impact_table["heating_fuel"] = property_instance.heating_energy_source
|
||||
kwh_impact_table["hotwater_fuel"] = property_instance.hot_water_energy_source
|
||||
ASHP_COP = 3
|
||||
descriptions_to_fuel_types = {
|
||||
"Air source heat pump, radiators, electric": {"fuel": "Electricity", "cop": ASHP_COP},
|
||||
"Boiler and radiators, mains gas": {"fuel": 'Natural Gas', "cop": 0.9}
|
||||
}
|
||||
|
||||
def map_descriptions_to_fuel(heating_description, hotwater_description):
|
||||
mapped = descriptions_to_fuel_types[heating_description]
|
||||
heating_fuel = mapped["fuel"]
|
||||
|
||||
if hotwater_description == "From main system":
|
||||
return {
|
||||
"heating_fuel_type": heating_fuel, "hotwater_fuel_type": heating_fuel,
|
||||
"heating_cop": mapped["cop"], "hotwater_cop": mapped["cop"]
|
||||
}
|
||||
|
||||
raise NotImplementedError("Implement me")
|
||||
|
||||
# For heating system recommendations, this could result in a fuel type change so we reflect that
|
||||
fuel_mapping = pd.DataFrame([
|
||||
{
|
||||
"id": epc["id"],
|
||||
**map_descriptions_to_fuel(epc["mainheat-description"], epc["hotwater-description"])
|
||||
} for epc in property_instance.updated_simulation_epcs
|
||||
])
|
||||
|
||||
fuel_mapping = pd.concat(
|
||||
[
|
||||
pd.DataFrame(
|
||||
[
|
||||
{
|
||||
"id": starting_dummy_id_value,
|
||||
**map_descriptions_to_fuel(
|
||||
property_instance.data["mainheat-description"],
|
||||
property_instance.data["hotwater-description"]
|
||||
)
|
||||
}
|
||||
]
|
||||
),
|
||||
fuel_mapping
|
||||
]
|
||||
)
|
||||
|
||||
kwh_impact_table = kwh_impact_table.merge(
|
||||
fuel_mapping, how="left", on="id"
|
||||
).sort_values(["phase", "recommendation_id"], ascending=True).reset_index(drop=True)
|
||||
|
||||
kwh_impact_table["heating_fuel_type"] = np.where(
|
||||
kwh_impact_table["id"] == starting_dummy_id_value,
|
||||
property_instance.heating_energy_source,
|
||||
kwh_impact_table["heating_fuel_type"]
|
||||
)
|
||||
|
||||
kwh_impact_table["hotwater_fuel_type"] = np.where(
|
||||
kwh_impact_table["id"] == starting_dummy_id_value,
|
||||
property_instance.hot_water_energy_source,
|
||||
kwh_impact_table["hotwater_fuel_type"]
|
||||
)
|
||||
|
||||
def calculate_recommendation_fuel_cost(kwh, fuel, cop):
|
||||
if fuel == "Electricity":
|
||||
return (kwh / cop) * AnnualBillSavings.ELECTRICITY_PRICE_CAP
|
||||
|
||||
if fuel == "Natural Gas":
|
||||
return (kwh / cop) * AnnualBillSavings.GAS_PRICE_CAP
|
||||
|
||||
# We now calculate the fuel cost
|
||||
for k in ["heating", "hotwater"]:
|
||||
kwh_impact_table[f"{k}_cost"] = kwh_impact_table.apply(
|
||||
lambda x: calculate_recommendation_fuel_cost(
|
||||
x[f"adjusted_{k}"], x[f"{k}_fuel_type"], x[f"{k}_cop"]
|
||||
), axis=1
|
||||
)
|
||||
|
||||
# TODO: The impact of remapping EPC is huge!
|
||||
|
||||
# We now deduce if any of the recommendations result in a change of fuel type
|
||||
for recs in property_recommendations:
|
||||
for rec in recs:
|
||||
print(rec["description_simulation"])
|
||||
if rec["type"] == "mechanical_ventilation":
|
||||
continue
|
||||
|
||||
rec_impact = kwh_impact_table[kwh_impact_table["recommendation_id"] == rec["recommendation_id"]]
|
||||
prevous_phase_id = (rec["phase"] - 1) if (rec["phase"] > 0) else starting_dummy_id_value
|
||||
previous_phase_impact = kwh_impact_table[kwh_impact_table["phase"] == prevous_phase_id]
|
||||
|
||||
if rec["type"] == "solar_pv":
|
||||
rec["kwh_savings"] = rec_impact["solar_kwh_savings"].values[0]
|
||||
rec["energy_cost_savings"] = (
|
||||
rec_impact["solar_kwh_savings"].values[0] * AnnualBillSavings.ELECTRICITY_PRICE_CAP
|
||||
)
|
||||
continue
|
||||
|
||||
heating_kwh_savings = (
|
||||
previous_phase_impact["adjusted_heating"].mean() - rec_impact["adjusted_heating"].values[0]
|
||||
)
|
||||
heating_cost_savings = (
|
||||
previous_phase_impact["heating_cost"].mean() - rec_impact["heating_cost"].values[0]
|
||||
)
|
||||
|
||||
hotwater_kwh_savings = (
|
||||
previous_phase_impact["adjusted_hotwater"].mean() - rec_impact["adjusted_hotwater"].values[0]
|
||||
)
|
||||
hotwater_host = (
|
||||
previous_phase_impact["hotwater_cost"].mean() - rec_impact["hotwater_cost"].values[0]
|
||||
)
|
||||
|
||||
total_kwh_savings = heating_kwh_savings + hotwater_kwh_savings
|
||||
energy_cost_savings = heating_cost_savings + hotwater_host
|
||||
|
||||
if rec["type"] == "lighting":
|
||||
# In this case, we should probably just SKIP but check when we have one!
|
||||
raise Exception("Implement me 3")
|
||||
|
||||
rec["kwh_savings"] = total_kwh_savings
|
||||
rec["energy_cost_savings"] = energy_cost_savings
|
||||
|
||||
# TODO: Given the default recommendations, calcualte a total kwh and cost saving for the property!!!
|
||||
|
||||
# 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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue