From 6562b69602c9183107ad27c33b3fc95145c840a2 Mon Sep 17 00:00:00 2001 From: hannesdiedrich Date: Wed, 2 Oct 2024 15:32:08 +0200 Subject: [PATCH 1/4] GSYE-568: Change hierarchy self consumption into percentage values --- src/gsy_e/gsy_e_core/export.py | 2 +- .../gsy_e_core/sim_results/endpoint_buffer.py | 33 ++++++++++++++----- tests/test_endpoint_buffers.py | 10 +++--- 3 files changed, 30 insertions(+), 15 deletions(-) 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..49e5c7b63 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, } @@ -195,14 +196,28 @@ 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) + hierarchy_self_consumption = {} + self._calc_hierarchy_self_consumption(area, 0, hierarchy_self_consumption_list) for level, consumption_list in hierarchy_self_consumption_list.items(): if len(consumption_list): - self.hierarchy_self_consumption[level] = sum(consumption_list) / len( - consumption_list - ) - - def _calc_hierarchy_stats(self, area: "AreaBase", level: int, results: Dict): + hierarchy_self_consumption[level] = sum(consumption_list) / len(consumption_list) + for level, self_consumption in hierarchy_self_consumption.items(): + if level + 1 not in 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 +230,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": "", From b55266d36d02b737129308cb53455d805c9e0e70 Mon Sep 17 00:00:00 2001 From: hannesdiedrich Date: Wed, 2 Oct 2024 15:59:36 +0200 Subject: [PATCH 2/4] GSYE-568: Return early in case if there is no self consumption --- src/gsy_e/gsy_e_core/sim_results/endpoint_buffer.py | 5 +++++ 1 file changed, 5 insertions(+) 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 49e5c7b63..2b7fd28af 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 @@ -201,6 +201,11 @@ def create_hierarchy_stats(self, area: "AreaBase"): for level, consumption_list in hierarchy_self_consumption_list.items(): if len(consumption_list): hierarchy_self_consumption[level] = sum(consumption_list) / len(consumption_list) + + if len(hierarchy_self_consumption) > 0 and next(iter(hierarchy_self_consumption)) == 0: + # early return in case there is no self consumpton at all (in order to not devide by 0) + return + for level, self_consumption in hierarchy_self_consumption.items(): if level + 1 not in hierarchy_self_consumption: # lowest level case: From d4ea7d71e07ad00f8170e1af332d5542eb045f7a Mon Sep 17 00:00:00 2001 From: hannesdiedrich Date: Mon, 7 Oct 2024 09:09:14 +0200 Subject: [PATCH 3/4] GSYE-568: Fix early return --- src/gsy_e/gsy_e_core/sim_results/endpoint_buffer.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 2b7fd28af..f6757e197 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 @@ -201,8 +201,10 @@ def create_hierarchy_stats(self, area: "AreaBase"): for level, consumption_list in hierarchy_self_consumption_list.items(): if len(consumption_list): hierarchy_self_consumption[level] = sum(consumption_list) / len(consumption_list) - - if len(hierarchy_self_consumption) > 0 and next(iter(hierarchy_self_consumption)) == 0: + if ( + len(hierarchy_self_consumption) > 0 + and hierarchy_self_consumption[next(iter(hierarchy_self_consumption))] == 0 + ): # early return in case there is no self consumpton at all (in order to not devide by 0) return From 87ff961819ddf20482f0f1f6fd929f622c390d18 Mon Sep 17 00:00:00 2001 From: hannesdiedrich Date: Mon, 7 Oct 2024 10:30:29 +0200 Subject: [PATCH 4/4] GSYE-568: Adapt to review comments --- .../gsy_e_core/sim_results/endpoint_buffer.py | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) 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 f6757e197..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 @@ -195,21 +195,18 @@ def _create_results_handler(should_export_plots): def create_hierarchy_stats(self, area: "AreaBase"): """Calculate hierarchy related statistics.""" - hierarchy_self_consumption_list = {} - hierarchy_self_consumption = {} - self._calc_hierarchy_self_consumption(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): - hierarchy_self_consumption[level] = sum(consumption_list) / len(consumption_list) - if ( - len(hierarchy_self_consumption) > 0 - and hierarchy_self_consumption[next(iter(hierarchy_self_consumption))] == 0 - ): - # early return in case there is no self consumpton at all (in order to not devide by 0) + 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 - for level, self_consumption in hierarchy_self_consumption.items(): - if level + 1 not in hierarchy_self_consumption: + 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]