From 14450f2b795e642e51fbccf6bea1b9208b62345f Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Tue, 9 Jul 2024 21:54:11 +0100 Subject: [PATCH] got the recommendation impact working for pfp --- backend/Property.py | 2 +- backend/app/plan/router.py | 4 +- recommendations/Recommendations.py | 176 ++++++++++++++++++----------- 3 files changed, 115 insertions(+), 67 deletions(-) diff --git a/backend/Property.py b/backend/Property.py index 9eb8ef99..b1cf2d16 100644 --- a/backend/Property.py +++ b/backend/Property.py @@ -739,7 +739,7 @@ class Property: self.current_adjusted_energy = ( adjusted_heating_kwh + adjusted_hot_water_kwh + adjusted_lighting_kwh + adjusted_applicances_kwh ) - self.expected_energy_bill = ( + self.current_energy_bill = ( adjusted_heating_cost + adjusted_hot_water_cost + adjusted_lighting_cost + adjusted_appliances_cost ) diff --git a/backend/app/plan/router.py b/backend/app/plan/router.py index e4fc508c..0fe50538 100644 --- a/backend/app/plan/router.py +++ b/backend/app/plan/router.py @@ -501,7 +501,9 @@ async def trigger_plan(body: PlanTriggerRequest): Recommendations.calculate_recommendation_impact( property_instance=property_instance, all_predictions=all_predictions, - recommendations=recommendations + recommendations=recommendations, + representative_recommendations=representative_recommendations, + energy_consumption_client=energy_consumption_client ) ) diff --git a/recommendations/Recommendations.py b/recommendations/Recommendations.py index 5cca056f..97e5a3b7 100644 --- a/recommendations/Recommendations.py +++ b/recommendations/Recommendations.py @@ -277,9 +277,71 @@ class Recommendations: return property_recommendations + @staticmethod + def _calculate_appliance_solar_savings( + rec, property_instance, heating_kwh_reduction, hot_water_kwh_reduction, lighting_kwh_reduction + ): + """ + Calculates the impact on kwh and cost of installing solar panels on appliances + :param rec: The recommendation + :param property_instance: Instance of the Property class + :param heating_kwh_reduction: The kwh reduction from heating + :param hot_water_kwh_reduction: The kwh reduction from hot water + :param lighting_kwh_reduction: The kwh reduction from lighting + :return: + """ + + if rec["type"] != "solar_pv": + return 0, 0 + + # 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 + ) + + return predicted_appliances_cost_reduction, predicted_appliances_kwh_reduction + @classmethod def calculate_recommendation_impact( - cls, property_instance, all_predictions, recommendations, energy_consumption_client + cls, + property_instance, + all_predictions, + recommendations, + representative_recommendations, + energy_consumption_client ): """ @@ -289,6 +351,7 @@ class Recommendations: :param property_instance: Instance of the Property class, for the home associated to property_id :param all_predictions: dictionary of predictions from the model apis :param recommendations: dictionary of recommendations for the property + :param representative_recommendations: dictionary of representative recommendations for the property :param energy_consumption_client: Instance of the EnergyConsumptionClient class :return: """ @@ -350,8 +413,14 @@ class Recommendations: ].median().reset_index() ) + representative_rec_ids = [ + rec["recommendation_id"] for rec in representative_recommendations[property_instance.id] + ] + phase_lighting_costs = {} phase_kwh_figures = {} + bill_savings_list = [] + kwh_savings_list = [] for recommendations_by_type in property_recommendations: for rec in recommendations_by_type: @@ -447,21 +516,6 @@ class Recommendations: "unadjusted": scoring_lighting_cost } - # This is the total bill savings for the recommendation - if rec["type"] == "solar_pv": - # We need to calculate the predicted bill savings for the solar pv recommendation - # where we will get some savings from the cost of appliances but it depends on the amount - # of energy generated by the solar panels - # We can assume that 50% of the energy generated will be used by the property without - # a battery, to be conservative. - # SIMILARLY: We need to handle kwh savings - raise Exception("Handle me") - else: - predicted_bill_savings = ( - predicted_heating_cost_reduction + predicted_hot_water_cost_reduction + - predicted_lighting_cost_reduction - ) - # We now predict the kwh savings using the xgb model simulation_epc = property_instance.simulation_epcs[rec["phase"]].copy() @@ -507,7 +561,30 @@ class Recommendations: lighting_kwh_reduction = predicted_lighting_cost_reduction / AnnualBillSavings.ELECTRICITY_PRICE_CAP - kwh_reduction = heating_kwh_reduction + hot_water_kwh_reduction + lighting_kwh_reduction + ( + predicted_appliances_cost_reduction, + predicted_appliances_kwh_reduction + ) = cls._calculate_appliance_solar_savings( + rec=rec, + property_instance=property_instance, + heating_kwh_reduction=heating_kwh_reduction, + hot_water_kwh_reduction=hot_water_kwh_reduction, + lighting_kwh_reduction=lighting_kwh_reduction + ) + + kwh_reduction = ( + heating_kwh_reduction + + hot_water_kwh_reduction + + lighting_kwh_reduction + + predicted_appliances_kwh_reduction + ) + + predicted_bill_savings = ( + predicted_heating_cost_reduction + + predicted_hot_water_cost_reduction + + predicted_lighting_cost_reduction + + predicted_appliances_cost_reduction + ) phase_kwh_figures[rec["phase"]] = { "adjusted": { @@ -651,48 +728,16 @@ class Recommendations: 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 - ) + ( + predicted_appliances_cost_reduction, + predicted_appliances_kwh_reduction + ) = cls._calculate_appliance_solar_savings( + rec=rec, + property_instance=property_instance, + heating_kwh_reduction=heating_kwh_reduction, + hot_water_kwh_reduction=hot_water_kwh_reduction, + lighting_kwh_reduction=lighting_kwh_reduction + ) # We now calculate the predicted_bill_savings predicted_bill_savings = ( @@ -723,17 +768,18 @@ class Recommendations: rec["kwh_savings"] = kwh_reduction rec["energy_cost_savings"] = predicted_bill_savings + if rec["recommendation_id"] in representative_rec_ids: + bill_savings_list.append(predicted_bill_savings) + kwh_savings_list.append(kwh_reduction) + if (rec["sap_points"] is None) and (rec["co2_equivalent_savings"] is None) or ( rec["heat_demand"] is None) or (rec["energy_cost_savings"] is None): raise ValueError("sap points, co2 or heat demand is missing") # We sum up the total savings for the property and that is our expected energy bill - # expected_energy_bill = sum( - # [ - # rec["energy_cost_savings"] for rec in property_recommendations - # if rec["type"] != "mechanical_ventilation" - # ] - # ) + + expected_energy_bill = property_instance.current_energy_bill - sum(bill_savings_list) + expected_adjusted_energy = property_instance.current_adjusted_energy - sum(kwh_savings_list) return ( property_recommendations,