From 0097cee2bac5a14d216f992db14ddbca4e0b5c21 Mon Sep 17 00:00:00 2001 From: Marcus Wood Date: Thu, 7 Aug 2025 10:22:01 +0100 Subject: [PATCH 1/3] Include EV load in the total load. EV is on a separate feeder --- src/skypro/commands/report/microgrid_flow_calcs.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/skypro/commands/report/microgrid_flow_calcs.py b/src/skypro/commands/report/microgrid_flow_calcs.py index fcbe805..7323065 100644 --- a/src/skypro/commands/report/microgrid_flow_calcs.py +++ b/src/skypro/commands/report/microgrid_flow_calcs.py @@ -47,6 +47,7 @@ def calc_flows( df["bess_net"] = df["bess_charge"] - df["bess_discharge"] # Taking the net of the EV circuit is probably overkill as the EVs shouldn't be exporting + df["ev_load"] = readings.ev_meter["energy_imported_active_delta"] df["ev_net"] = readings.ev_meter["energy_imported_active_delta"] - readings.ev_meter["energy_exported_active_delta"] df["feeder1_net"] = readings.feeder1_meter["energy_imported_active_delta"] - readings.feeder1_meter["energy_exported_active_delta"] @@ -101,7 +102,7 @@ def calc_flows( notices.extend(new_notices) df["solar"] = df[["solar_feeder1", "solar_feeder2"]].sum(axis=1) - df["load"] = df[["plot_load_feeder1", "plot_load_feeder2"]].sum(axis=1) + df["load"] = df[["plot_load_feeder1", "plot_load_feeder2", "ev_load"]].sum(axis=1) df["solar_to_load"] = np.minimum(df["solar"], df["load"]) # requires emlite data # These columns are required for the output CSV, and could be calculated, but there's not currently a need for it From 478e6cc1346fb4e95321e98432442ae9a706c06b Mon Sep 17 00:00:00 2001 From: Marcus Wood Date: Thu, 7 Aug 2025 10:39:37 +0100 Subject: [PATCH 2/3] Include load energy breakdown in reporting CSV --- src/skypro/commands/report/main.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/skypro/commands/report/main.py b/src/skypro/commands/report/main.py index 03eb360..f857381 100644 --- a/src/skypro/commands/report/main.py +++ b/src/skypro/commands/report/main.py @@ -115,6 +115,14 @@ def file_path_resolver_func(file: str) -> str: if do_plots: plot_load_and_solar(result.df) + # This dataframe determines how the load is broken down in the output file - here we configure three different sub-components + # of load, so we will get CSV columns for load.feeder1, load.feeder2, and load.ev. + load_energy_breakdown_df = result.df[["plot_load_feeder1", "plot_load_feeder2", "ev_load"]].rename(columns={ + "plot_load_feeder1": "feeder1", + "plot_load_feeder2": "feeder2", + "ev_load": "ev" + }) + if output_file_path: # The main output file has half-hour granularity generate_output_df( df=result.df, @@ -125,7 +133,7 @@ def file_path_resolver_func(file: str) -> str: mkt_fixed_costs_dfs=result.mkt_fixed_cost_dfs, customer_fixed_cost_dfs=result.customer_fixed_cost_dfs, customer_vol_rates_dfs=result.customer_vol_rates_dfs, - load_energy_breakdown_df=None, + load_energy_breakdown_df=load_energy_breakdown_df, aggregate_timebase="30min", rate_detail=None, config_entries=[], @@ -135,6 +143,7 @@ def file_path_resolver_func(file: str) -> str: ) if summary_output_file_path: # The summary output file has a single row to summarise the entire report + generate_output_df( df=result.df, int_final_vol_rates_dfs=result.int_vol_rates_dfs, @@ -144,7 +153,7 @@ def file_path_resolver_func(file: str) -> str: mkt_fixed_costs_dfs=result.mkt_fixed_cost_dfs, customer_fixed_cost_dfs=result.customer_fixed_cost_dfs, customer_vol_rates_dfs=result.customer_vol_rates_dfs, - load_energy_breakdown_df=None, + load_energy_breakdown_df=load_energy_breakdown_df, aggregate_timebase="all", rate_detail=None, config_entries=[], From bb2997ff7f8b343964f29806665c88571a3c744d Mon Sep 17 00:00:00 2001 From: Marcus Wood Date: Thu, 7 Aug 2025 10:41:35 +0100 Subject: [PATCH 3/3] Fix reporting integration tests --- src/tests/integration/test_integration_reporting.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/tests/integration/test_integration_reporting.py b/src/tests/integration/test_integration_reporting.py index 8a0dbeb..0258825 100644 --- a/src/tests/integration/test_integration_reporting.py +++ b/src/tests/integration/test_integration_reporting.py @@ -26,7 +26,7 @@ class SubTest: msg="report202408", month="2024-08", expected_summary_df=pd.DataFrame.from_dict({ - "agd:load": [9290.688], + "agd:load": [9755.188], "agd:solar": [21969.16780], "m:upImport": [31385.62743], "m:upExport": [38970.21875], @@ -34,12 +34,15 @@ class SubTest: "m:battDischarge": [26568.10938], "c:solarToGrid": [12384.01863], "c:gridToLoad": [4571.26804], - "c:solarToLoad": [4860.90924], + "c:solarToLoad": [5002.03904], "c:battToLoad": [456.48816], "c:battToGrid": [26111.62122], "c:solarToBatt": [4583.11013], "c:gridToBatt": [26339.78050], "other:osam.ncsp": [0.96923], + "agd:load.feeder1": [3446.75500], + "agd:load.feeder2": [5843.93300], + "agd:load.ev": [464.50000], "mfCost:import": [48050.00000], "mfCost:export": [0.00000], "cfCost:all": [-62000.00000], @@ -50,7 +53,7 @@ class SubTest: "ivRate:gridToLoad.final": [0.00000], "ivRate:solarToBatt.final": [3.88745], "ivRate:battToLoad.final": [-19.21144], - "ivRate:solarToLoad.final": [-10.17220], + "ivRate:solarToLoad.final": [-10.17701], "mvRate:solarToBatt.final": [0.00000], "mvRate:gridToBatt.final": [6.00367], "mvRate:battToLoad.final": [0.00000], @@ -88,7 +91,7 @@ class SubTest: columns_to_compare = sub.expected_summary_df.columns df = df[columns_to_compare] - + error = (df - sub.expected_summary_df).abs() tolerance = 0.01