diff --git a/src/gsy_e/gsy_e_core/export.py b/src/gsy_e/gsy_e_core/export.py index 0b0ab5d77..1c47a09af 100644 --- a/src/gsy_e/gsy_e_core/export.py +++ b/src/gsy_e/gsy_e_core/export.py @@ -83,7 +83,7 @@ "status": "status", "trade_profile": "trade_profile", "imported_exported_energy": "imported_exported_energy", - "hierarchy_self_consumption": "hierarchy_self_consumption", + "hierarchy_self_consumption_percent": "hierarchy_self_consumption_percent", } diff --git a/src/gsy_e/gsy_e_core/sim_results/endpoint_buffer.py b/src/gsy_e/gsy_e_core/sim_results/endpoint_buffer.py index d63e87d2b..fc3eb9730 100644 --- a/src/gsy_e/gsy_e_core/sim_results/endpoint_buffer.py +++ b/src/gsy_e/gsy_e_core/sim_results/endpoint_buffer.py @@ -19,6 +19,7 @@ import logging from collections import defaultdict from typing import TYPE_CHECKING, Dict, Iterable, List +from math import isclose from gsy_framework.constants_limits import ( DATE_TIME_FORMAT, @@ -94,7 +95,7 @@ def __init__(self, job_id, random_seed, area, should_export_plots): self.status = "" self.area_result_dict = self._create_area_tree_dict(area) self.flattened_area_core_stats_dict = {} - self.hierarchy_self_consumption: Dict[int, float] = {} + self.hierarchy_self_consumption_percent: Dict[int, float] = {} self.simulation_progress = { "eta_seconds": 0, "elapsed_time_seconds": 0, @@ -135,7 +136,7 @@ def generate_json_report(self) -> Dict: "status": self.status, "progress_info": self.simulation_progress, "simulation_state": self.simulation_state, - "hierarchy_self_consumption": self.hierarchy_self_consumption, + "hierarchy_self_consumption_percent": self.hierarchy_self_consumption_percent, **self.results_handler.all_raw_results, } @@ -194,15 +195,33 @@ def _create_results_handler(should_export_plots): def create_hierarchy_stats(self, area: "AreaBase"): """Calculate hierarchy related statistics.""" - hierarchy_self_consumption_list = {} - self._calc_hierarchy_stats(area, 0, hierarchy_self_consumption_list) - for level, consumption_list in hierarchy_self_consumption_list.items(): + hierarchy_self_consumption_lists = {} + hierarchy_self_consumption = [] + self._calc_hierarchy_self_consumption(area, 0, hierarchy_self_consumption_lists) + for level, consumption_list in hierarchy_self_consumption_lists.items(): if len(consumption_list): - self.hierarchy_self_consumption[level] = sum(consumption_list) / len( - consumption_list - ) + hierarchy_self_consumption.append(sum(consumption_list) / len(consumption_list)) + if len(hierarchy_self_consumption) > 0 and hierarchy_self_consumption[0] == 0: + # early return in case there is no self consumption at all (not devide by 0) + return - def _calc_hierarchy_stats(self, area: "AreaBase", level: int, results: Dict): + for level, self_consumption in enumerate(hierarchy_self_consumption): + if level + 1 >= len(hierarchy_self_consumption): + # lowest level case: + self.hierarchy_self_consumption_percent[level] = ( + self_consumption / hierarchy_self_consumption[0] + ) * 100 + else: + self.hierarchy_self_consumption_percent[level] = ( + (self_consumption - hierarchy_self_consumption[level + 1]) + / hierarchy_self_consumption[0] + ) * 100 + if self.hierarchy_self_consumption_percent: + assert isclose( + sum(self.hierarchy_self_consumption_percent.values()), 100 + ), "Self consumption percentages do not sum up to 100%" + + def _calc_hierarchy_self_consumption(self, area: "AreaBase", level: int, results: Dict): if not area.children: return kpis = self.results_handler.results_mapping["kpi"].ui_formatted_results @@ -215,7 +234,7 @@ def _calc_hierarchy_stats(self, area: "AreaBase", level: int, results: Dict): if level not in results: results[level] = [] results[level].append(kpis[child.uuid]["self_consumption"]) - self._calc_hierarchy_stats(child, level + 1, results) + self._calc_hierarchy_self_consumption(child, level + 1, results) def _generate_result_report(self) -> Dict: """Create dict that contains all statistics that are sent to the gsy-web.""" diff --git a/tests/test_endpoint_buffers.py b/tests/test_endpoint_buffers.py index 0bcd7945e..1176c28a8 100644 --- a/tests/test_endpoint_buffers.py +++ b/tests/test_endpoint_buffers.py @@ -254,7 +254,7 @@ def test_generate_json_report_returns_successfully(self, general_setup): endpoint_buffer.results_handler = results_handler_mock assert endpoint_buffer.generate_json_report() == { - "hierarchy_self_consumption": {}, + "hierarchy_self_consumption_percent": {}, "job_id": "JOB_1", "random_seed": 41, "status": "", @@ -353,11 +353,11 @@ def test_update_stats_spot_markets_updates_successfully(self, general_setup): def _create_kpis(area): kpis = defaultdict(dict) for n_city, city in enumerate(area.children): - kpis[city.uuid]["self_consumption"] = n_city * 10 + kpis[city.uuid]["self_consumption"] = (n_city + 2) * 10 for n_community, community in enumerate(city.children): kpis[community.uuid]["self_consumption"] = (n_community + 1) * 10 for n_house, house in enumerate(community.children): - kpis[house.uuid]["self_consumption"] = (n_house + 2) * 10 + kpis[house.uuid]["self_consumption"] = n_house * 10 return kpis def test_create_hierarchy_stats_returns_correct_results(self, setup_multiple_levels): @@ -368,7 +368,7 @@ def test_create_hierarchy_stats_returns_correct_results(self, setup_multiple_lev endpoint_buffer.results_handler.results_mapping["kpi"].performance_indices_redis = kpis endpoint_buffer.create_hierarchy_stats(setup_multiple_levels) - assert endpoint_buffer.hierarchy_self_consumption == {0: 5.0, 1: 15.0, 2: 25.0} + assert endpoint_buffer.hierarchy_self_consumption_percent == {0: 40, 1: 40, 2: 20} class TestSimulationEndpointBufferForward: @@ -512,7 +512,7 @@ def test_generate_json_report_returns_successfully(self, forward_setup): endpoint_buffer.results_handler = results_handler_mock assert endpoint_buffer.generate_json_report() == { - "hierarchy_self_consumption": {}, + "hierarchy_self_consumption_percent": {}, "job_id": "JOB_1", "random_seed": 41, "status": "",