From fa1bf60f6fb41f6aa50d1afd947d35be4d6b835a Mon Sep 17 00:00:00 2001 From: frederikfristed <118888702+frederikfristed@users.noreply.github.com> Date: Wed, 2 Oct 2024 15:32:17 +0200 Subject: [PATCH] Added support for OptiFlow_MainResults (#18) * Added support for OptiFlow_MainResults * Columns never used, if input * Small cleanup * Release 0.3.12 --- docs/conf.py | 2 +- docs/get_started/installation.md | 2 +- environment.yaml | 2 +- pyproject.toml | 2 +- src/pybalmorel/classes.py | 9 +- src/pybalmorel/formatting.py | 172 +++++++++++------- .../interactive/interactive_functions.py | 13 +- src/pybalmorel/plotting/plot_functions.py | 11 +- src/pybalmorel/utils.py | 29 ++- 9 files changed, 163 insertions(+), 79 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 934aade..b6e5492 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,7 +1,7 @@ project = "pybalmorel" copyright = "2024, Mathias Berg Rosendal, Théodore Le Nalinec" author = "Mathias Berg Rosendal, Théodore Le Nalinec" -release = "0.3.11" +release = "0.3.12" exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", ".testenv", ".testenv/**"] diff --git a/docs/get_started/installation.md b/docs/get_started/installation.md index 402b3b8..4fd8980 100644 --- a/docs/get_started/installation.md +++ b/docs/get_started/installation.md @@ -21,5 +21,5 @@ dependencies: - pip: - gamsapi[transfer]>=45.7.0 - eel>=0.17.0 - - pybalmorel==0.3.11 + - pybalmorel==0.3.12 ``` diff --git a/environment.yaml b/environment.yaml index ee14166..4711e55 100644 --- a/environment.yaml +++ b/environment.yaml @@ -12,4 +12,4 @@ dependencies: - pip: - gamsapi[transfer]>=45.7.0 - eel>=0.17.0 - - pybalmorel==0.3.11 + - pybalmorel==0.3.12 diff --git a/pyproject.toml b/pyproject.toml index 7fe2b4f..8018634 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "pybalmorel" -version = "0.3.11" +version = "0.3.12" maintainers = [ { name="Mathias Berg Rosendal", email="mathiasros@gmail.com"}, { name="Théodore Le Nalinec"}, diff --git a/src/pybalmorel/classes.py b/src/pybalmorel/classes.py index b2e1598..8b7795a 100644 --- a/src/pybalmorel/classes.py +++ b/src/pybalmorel/classes.py @@ -31,7 +31,8 @@ class MainResults: def __init__(self, files: Union[str, list, tuple], paths: Union[str, list, tuple] = '.', scenario_names: Union[str, list, tuple] = None, - system_directory: str = None): + system_directory: str = None, + result_type: str = 'balmorel'): """ Initialises the MainResults class and loads gdx result file(s) @@ -40,6 +41,7 @@ def __init__(self, files: Union[str, list, tuple], paths (str, list, tuple): Path(s) to the gdx result file(s), assumed in same path if only one path given, defaults to working directory scenario_names (str, list, tuple): Name of scenarios corresponding to each gdx file, defaults to ['SC1', 'SC2', ..., 'SCN'] if None given system_directory (str, optional): GAMS system directory. Is not used if not specified. + result_type (str, optional): Specifies the type of result to extract. Use 'optiflow' for OptiFlow results. If not specified, it defaults to extracting Balmorel GDX results. """ ## Loading scenarios @@ -83,11 +85,12 @@ def __init__(self, files: Union[str, list, tuple], if len(files) != len(scenario_names): # Raise error if not given same amount of scenario_names and files raise Exception("%d files, but %d scenario names given!\nProvide none or the same amount of scenario names as files"%(len(files), len(scenario_names))) - + ## Store MainResult databases self.files = files self.paths = paths self.sc = scenario_names + self.type = result_type self.db = {} if system_directory != None: @@ -116,7 +119,7 @@ def get_result(self, symbol: str, cols: str = 'None') -> pd.DataFrame: for SC in self.sc: # Get results from each scenario try : - temp = symbol_to_df(self.db[SC], symbol, cols) + temp = symbol_to_df(self.db[SC], symbol, cols, result_type=self.type) temp['Scenario'] = SC # Put scenario in first column temp = temp.loc[:, ['Scenario'] + list(temp.columns[:-1])] diff --git a/src/pybalmorel/formatting.py b/src/pybalmorel/formatting.py index 6469e2e..47468b4 100644 --- a/src/pybalmorel/formatting.py +++ b/src/pybalmorel/formatting.py @@ -116,64 +116,114 @@ ### 2. Other ### ### ------------------------------- ### -mainresult_symbol_columns = {'F_CONS_YCRA': ['Year','Country','Region','Area','Generation','Fuel','Technology'], - 'F_CONS_YCRAST': ['Year','Country','Region','Area','Generation','Fuel','Season','Time','Technology'], - 'G_CAP_YCRAF': ['Year','Country','Region','Area','Generation','Fuel','Commodity','Technology','Category'], - 'EL_DEMAND_YCR': ['Year','Country','Region','Category'], - 'EL_DEMAND_YCRST': ['Year','Country','Region','Season','Time','Category'], - 'EL_PRICE_YCR': ['Year','Country','Region'], - 'EL_PRICE_YCRST': ['Year','Country','Region','Season','Time'], - 'G_STO_YCRAF': ['Year','Country','Region','Area','Generation','Fuel','Commodity','Technology','Category'], - 'EL_BALANCE_YCRST':['Year','Country','Region','Technology','Season','Time'], - 'H2_DEMAND_YCR': ['Year','Country','Region','Category'], - 'H2_DEMAND_YCRST': ['Year','Country','Region','Season','Time','Category'], - 'H2_PRICE_YCR': ['Year','Country','Region','Category'], - 'H2_DEMAND_YCRST': ['Year','Country','Region','Season','Time','Category'], - 'H_BALANCE_YCRAST':['Year','Country','Region','Area','Technology','Season','Time'], - 'H_DEMAND_YCRA': ['Year','Country','Region','Area','Category'], - 'H_DEMAND_YCRAST': ['Year','Country','Region','Area','Season','Time','Category'], - 'H_PRICE_YCRA': ['Year','Country','Region','Area','Category'], - 'H_PRICE_YCRAST': ['Year','Country','Region','Area','Season','Time'], - 'OBJ_YCR': ['Year','Country','Region','Category'], - 'PRO_YCRAGF': ['Year','Country','Region','Area','Generation','Fuel','Commodity','Technology'], - 'PRO_YCRAGFST': ['Year','Country','Region','Area','Generation','Fuel','Season','Time','Commodity','Technology'], - 'X_CAP_YCR': ['Year','Country','From','To','Category'], - 'X_FLOW_YCR': ['Year','Country','From','To'], - 'X_FLOW_YCRST': ['Year','Country','From','To','Season','Time'], - 'XH2_CAP_YCR': ['Year','Country','From','To','Category'], - 'XH2_FLOW_YCR': ['Year','Country','From','To'], - 'XH2_FLOW_YCRST': ['Year','Country','From','To','Season','Time'], - 'XH_CAP_YCA': ['Year','Country','From','To','Category'], - 'XH_FLOW_YCA': ['Year','Country','From','To'], - 'XH_FLOW_YCAST': ['Year','Country','From','To','Season','Time']} - -mainresults_symbol_columns = {'F_CONS_YCRA': ['Scenario', 'Year','Country','Region','Area','Generation','Fuel','Technology'], - 'F_CONS_YCRAST': ['Scenario', 'Year','Country','Region','Area','Generation','Fuel','Season','Time','Technology'], - 'G_CAP_YCRAF': ['Scenario', 'Year','Country','Region','Area','Generation','Fuel','Commodity','Technology','Category'], - 'G_STO_YCRAF': ['Scenario', 'Year','Country','Region','Area','Generation','Fuel','Commodity','Technology','Category'], - 'EL_DEMAND_YCR': ['Scenario', 'Year','Country','Region','Category'], - 'EL_DEMAND_YCRST': ['Scenario', 'Year','Country','Region','Season','Time','Category'], - 'EL_PRICE_YCR': ['Scenario', 'Year','Country','Region'], - 'EL_PRICE_YCRST': ['Scenario', 'Year','Country','Region','Season','Time'], - 'EL_BALANCE_YCRST':['Scenario', 'Year','Country','Region','Technology','Season','Time'], - 'H2_DEMAND_YCR': ['Scenario', 'Year','Country','Region','Category'], - 'H2_DEMAND_YCRST': ['Scenario', 'Year','Country','Region','Season','Time','Category'], - 'H2_PRICE_YCR': ['Scenario', 'Year','Country','Region','Category'], - 'H2_DEMAND_YCRST': ['Scenario', 'Year','Country','Region','Season','Time','Category'], - 'H_BALANCE_YCRAST':['Scenario', 'Year','Country','Region','Area','Technology','Season','Time'], - 'H_DEMAND_YCRA': ['Scenario', 'Year','Country','Region','Area','Category'], - 'H_DEMAND_YCRAST': ['Scenario', 'Year','Country','Region','Area','Season','Time','Category'], - 'H_PRICE_YCRA': ['Scenario', 'Year','Country','Region','Area','Category'], - 'H_PRICE_YCRAST': ['Scenario', 'Year','Country','Region','Area','Season','Time'], - 'OBJ_YCR': ['Scenario', 'Year','Country','Region','Category'], - 'PRO_YCRAGF': ['Scenario', 'Year','Country','Region','Area','Generation','Fuel','Commodity','Technology'], - 'PRO_YCRAGFST': ['Scenario', 'Year','Country','Region','Area','Generation','Fuel','Season','Time','Commodity','Technology'], - 'X_CAP_YCR': ['Scenario', 'Year','Country','From','To','Category'], - 'X_FLOW_YCR': ['Scenario', 'Year','Country','From','To'], - 'X_FLOW_YCRST': ['Scenario', 'Year','Country','From','To','Season','Time'], - 'XH2_CAP_YCR': ['Scenario', 'Year','Country','From','To','Category'], - 'XH2_FLOW_YCR': ['Scenario', 'Year','Country','From','To'], - 'XH2_FLOW_YCRST': ['Scenario', 'Year','Country','From','To','Season','Time'], - 'XH_CAP_YCA': ['Scenario', 'Year','Country','From','To','Category'], - 'XH_FLOW_YCA': ['Scenario', 'Year','Country','From','To'], - 'XH_FLOW_YCAST': ['Scenario', 'Year','Country','From','To','Season','Time']} \ No newline at end of file +#Balmorel +balmorel_symbol_columns = {'F_CONS_YCRA': ['Year','Country','Region','Area','Generation','Fuel','Technology'], + 'F_CONS_YCRAST': ['Year','Country','Region','Area','Generation','Fuel','Season','Time','Technology'], + 'G_CAP_YCRAF': ['Year','Country','Region','Area','Generation','Fuel','Commodity','Technology','Category'], + 'EL_DEMAND_YCR': ['Year','Country','Region','Category'], + 'EL_DEMAND_YCRST': ['Year','Country','Region','Season','Time','Category'], + 'EL_PRICE_YCR': ['Year','Country','Region'], + 'EL_PRICE_YCRST': ['Year','Country','Region','Season','Time'], + 'G_STO_YCRAF': ['Year','Country','Region','Area','Generation','Fuel','Commodity','Technology','Category'], + 'EL_BALANCE_YCRST':['Year','Country','Region','Technology','Season','Time'], + 'H2_DEMAND_YCR': ['Year','Country','Region','Category'], + 'H2_DEMAND_YCRST': ['Year','Country','Region','Season','Time','Category'], + 'H2_PRICE_YCR': ['Year','Country','Region','Category'], + 'H2_DEMAND_YCRST': ['Year','Country','Region','Season','Time','Category'], + 'H_BALANCE_YCRAST':['Year','Country','Region','Area','Technology','Season','Time'], + 'H_DEMAND_YCRA': ['Year','Country','Region','Area','Category'], + 'H_DEMAND_YCRAST': ['Year','Country','Region','Area','Season','Time','Category'], + 'H_PRICE_YCRA': ['Year','Country','Region','Area','Category'], + 'H_PRICE_YCRAST': ['Year','Country','Region','Area','Season','Time'], + 'OBJ_YCR': ['Year','Country','Region','Category'], + 'PRO_YCRAGF': ['Year','Country','Region','Area','Generation','Fuel','Commodity','Technology'], + 'PRO_YCRAGFST': ['Year','Country','Region','Area','Generation','Fuel','Season','Time','Commodity','Technology'], + 'X_CAP_YCR': ['Year','Country','From','To','Category'], + 'X_FLOW_YCR': ['Year','Country','From','To'], + 'X_FLOW_YCRST': ['Year','Country','From','To','Season','Time'], + 'XH2_CAP_YCR': ['Year','Country','From','To','Category'], + 'XH2_FLOW_YCR': ['Year','Country','From','To'], + 'XH2_FLOW_YCRST': ['Year','Country','From','To','Season','Time'], + 'XH_CAP_YCA': ['Year','Country','From','To','Category'], + 'XH_FLOW_YCA': ['Year','Country','From','To'], + 'XH_FLOW_YCAST': ['Year','Country','From','To','Season','Time'] +} + + +balmorel_mainresults_symbol_columns = {'F_CONS_YCRA': ['Scenario', 'Year','Country','Region','Area','Generation','Fuel','Technology'], + 'F_CONS_YCRAST': ['Scenario', 'Year','Country','Region','Area','Generation','Fuel','Season','Time','Technology'], + 'G_CAP_YCRAF': ['Scenario', 'Year','Country','Region','Area','Generation','Fuel','Commodity','Technology','Category'], + 'G_STO_YCRAF': ['Scenario', 'Year','Country','Region','Area','Generation','Fuel','Commodity','Technology','Category'], + 'EL_DEMAND_YCR': ['Scenario', 'Year','Country','Region','Category'], + 'EL_DEMAND_YCRST': ['Scenario', 'Year','Country','Region','Season','Time','Category'], + 'EL_PRICE_YCR': ['Scenario', 'Year','Country','Region'], + 'EL_PRICE_YCRST': ['Scenario', 'Year','Country','Region','Season','Time'], + 'EL_BALANCE_YCRST':['Scenario', 'Year','Country','Region','Technology','Season','Time'], + 'H2_DEMAND_YCR': ['Scenario', 'Year','Country','Region','Category'], + 'H2_DEMAND_YCRST': ['Scenario', 'Year','Country','Region','Season','Time','Category'], + 'H2_PRICE_YCR': ['Scenario', 'Year','Country','Region','Category'], + 'H2_DEMAND_YCRST': ['Scenario', 'Year','Country','Region','Season','Time','Category'], + 'H_BALANCE_YCRAST':['Scenario', 'Year','Country','Region','Area','Technology','Season','Time'], + 'H_DEMAND_YCRA': ['Scenario', 'Year','Country','Region','Area','Category'], + 'H_DEMAND_YCRAST': ['Scenario', 'Year','Country','Region','Area','Season','Time','Category'], + 'H_PRICE_YCRA': ['Scenario', 'Year','Country','Region','Area','Category'], + 'H_PRICE_YCRAST': ['Scenario', 'Year','Country','Region','Area','Season','Time'], + 'OBJ_YCR': ['Scenario', 'Year','Country','Region','Category'], + 'PRO_YCRAGF': ['Scenario', 'Year','Country','Region','Area','Generation','Fuel','Commodity','Technology'], + 'PRO_YCRAGFST': ['Scenario', 'Year','Country','Region','Area','Generation','Fuel','Season','Time','Commodity','Technology'], + 'X_CAP_YCR': ['Scenario', 'Year','Country','From','To','Category'], + 'X_FLOW_YCR': ['Scenario', 'Year','Country','From','To'], + 'X_FLOW_YCRST': ['Scenario', 'Year','Country','From','To','Season','Time'], + 'XH2_CAP_YCR': ['Scenario', 'Year','Country','From','To','Category'], + 'XH2_FLOW_YCR': ['Scenario', 'Year','Country','From','To'], + 'XH2_FLOW_YCRST': ['Scenario', 'Year','Country','From','To','Season','Time'], + 'XH_CAP_YCA': ['Scenario', 'Year','Country','From','To','Category'], + 'XH_FLOW_YCA': ['Scenario', 'Year','Country','From','To'], + 'XH_FLOW_YCAST': ['Scenario', 'Year','Country','From','To','Season','Time'] +} + +#Optiflow +optiflow_symbol_columns = {'ECO_INDIC': ['Year','Indicator'], + 'ECO_PROC_YCRAP': ['Year','Country','Region','Area','Process','Cost'], + 'EMI_PROC': ['Year','Country','Region','Area','Process','Flow'], + 'EMI_YCRAG': ['Year','Country','Region','Area','Generation','Fuel','Technology'], + 'OBJ_YCR': ['Year','Country','Region','Category'], + 'PRO_YCRAGF': ['Year','Country','Region','Area','Generation','Fuel','Commodity','Technology'], + 'PRO_YCRAGFST': ['Year','Country','Region','Area','Generation','Fuel','Season','Time','Commodity','Technology'], + 'RE_fuel_Price': ['Year','Country','Process','Flow'], + 'VFLOW_Opti_A': ['Year','Country','From','To','Flow'], + 'VFLOW_Opti_C': ['Year','Country','From','To','Flow'], + 'VFLOWBUFFER_Opti_C': ['Year','Buffer','Process','Flow'], + 'VFLOTCCU_A': ['Year','Area','Source','Flow'], + 'VFLOTCCU_C': ['Year','Country','Source','Flow'], + 'VFLOWSOURCE_Opti_A': ['Year','Area','Source','Flow'], + 'VFLOWSOURCE_Opti_C': ['Year','Country','Source','Flow'], + 'VFLOWSTORAGE_Opti_A': ['Year','Area','Process','Flow'], + 'VFLOWSTORAGE_Opti_C': ['Year','Country','Process','Flow'], + 'VFLOWTRANS_Opti_A': ['Year','From','To','Process','Flow'], + 'VFLOWTRANS_Opti_C': ['Year','From','To','Process','Flow'] +} + +optiflow_mainresults_symbol_columns = {'ECO_INDIC': ['Scenario','Year','Indicator'], + 'ECO_PROC_YCRAP': ['Scenario','Year','Country','Region','Area','Process','Cost'], + 'EMI_PROC': ['Scenario','Year','Country','Region','Area','Process','Flow'], + 'EMI_YCRAG': ['Scenario','Year','Country','Region','Area','Generation','Fuel','Technology'], + 'OBJ_YCR': ['Scenario','Year','Country','Region','Category'], + 'PRO_YCRAGF': ['Scenario','Year','Country','Region','Area','Generation','Fuel','Commodity','Technology'], + 'PRO_YCRAGFST': ['Scenario','Year','Country','Region','Area','Generation','Fuel','Season','Time','Commodity','Technology'], + 'RE_fuel_Price': ['Scenario','Year','Country','Process','Flow'], + 'VFLOW_Opti_A': ['Scenario','Year','Country','From','To','Flow'], + 'VFLOW_Opti_C': ['Scenario','Year','Country','From','To','Flow'], + 'VFLOWBUFFER_Opti_C': ['Scenario','Year','Buffer','Process','Flow'], + 'VFLOTCCU_A': ['Scenario','Year','Area','Source','Flow'], + 'VFLOTCCU_C': ['Scenario','Year','Country','Source','Flow'], + 'VFLOWSOURCE_Opti_A': ['Scenario','Year','Area','Source','Flow'], + 'VFLOWSOURCE_Opti_C': ['Scenario','Year','Country','Source','Flow'], + 'VFLOWSTORAGE_Opti_A': ['Scenario','Year','Area','Process','Flow'], + 'VFLOWSTORAGE_Opti_C': ['Scenario','Year','Country','Process','Flow'], + 'VFLOWTRANS_Opti_A': ['Scenario','Year','From','To','Process','Flow'], + 'VFLOWTRANS_Opti_C': ['Scenario','Year','From','To','Process','Flow'] +} + + + diff --git a/src/pybalmorel/interactive/interactive_functions.py b/src/pybalmorel/interactive/interactive_functions.py index 517da50..7acc0d1 100644 --- a/src/pybalmorel/interactive/interactive_functions.py +++ b/src/pybalmorel/interactive/interactive_functions.py @@ -20,8 +20,7 @@ import ipywidgets as widgets from ipywidgets import interact, interactive from ..plotting.plot_functions import plot_bar_chart -from ..formatting import mainresults_symbol_columns - +from ..formatting import optiflow_mainresults_symbol_columns, balmorel_mainresults_symbol_columns #%% ------------------------------- ### ### 1. Bar chart interactive ### @@ -35,6 +34,16 @@ def interactive_bar_chart(MainResults_instance): MainResults_instance (MainResults): Takes an instance of the MainResults class and opens a GUI for plotting """ + """Result type definition""" + result_type = MainResults_instance.type.lower() + print(f"Result type: {result_type}") + + # Initial selection for plotting + if result_type=='optiflow': + mainresults_symbol_columns=optiflow_mainresults_symbol_columns + elif result_type=='balmorel': + mainresults_symbol_columns=balmorel_mainresults_symbol_columns + """ Buttons definition """ # Initial selection for plotting diff --git a/src/pybalmorel/plotting/plot_functions.py b/src/pybalmorel/plotting/plot_functions.py index 996bfb0..d296652 100644 --- a/src/pybalmorel/plotting/plot_functions.py +++ b/src/pybalmorel/plotting/plot_functions.py @@ -42,9 +42,14 @@ def plot_bar_chart(df: pd.core.frame.DataFrame, filter: dict, series: Union[str, """ # Unit - unit = df['Unit'][0] + if 'Unit' in df.columns: + unit = df['Unit'][0] # Get the first unit value if the column exists + else: + unit = None # Set to an empty list + + # Continue with unit_dict as normal unit_dict = {'GW': 'Capacity', 'TWh': 'Energy', 'GWh': 'Energy'} - + # Filtering the dataframe query_parts = [] for key, value in filter.items(): @@ -226,6 +231,8 @@ def custom_sort_key(item): else : if unit in unit_dict: ax.set_ylabel(f'{unit_dict[unit]} ({unit})', fontsize=yaxis[1]) + elif unit==None: + ax.set_ylabel(f'Value', fontsize=yaxis[1]) else : ax.set_ylabel(f'Value ({unit})', fontsize=yaxis[1]) diff --git a/src/pybalmorel/utils.py b/src/pybalmorel/utils.py index 144be42..b900fbc 100644 --- a/src/pybalmorel/utils.py +++ b/src/pybalmorel/utils.py @@ -4,7 +4,7 @@ import gams import pandas as pd -from .formatting import mainresult_symbol_columns +from .formatting import balmorel_symbol_columns, optiflow_symbol_columns #%% ------------------------------- ### ### 1. GAMS Interface ### @@ -12,7 +12,9 @@ ### 1.0 Converting a GDX file to a pandas dataframe def symbol_to_df(db: gams.GamsDatabase, symbol: str, - cols: str = 'None', parameter_or_set: str = 'parameter'): + cols: str = 'None', + parameter_or_set: str = 'parameter', + result_type: str = 'balmorel'): """ Loads a symbol from a GDX database into a pandas dataframe @@ -30,16 +32,29 @@ def symbol_to_df(db: gams.GamsDatabase, symbol: str, else: print('Choose either parameter or set!') + ## Format by result type + result_type = result_type.lower() + + if result_type=='balmorel': + mainresult_symbol_columns = balmorel_symbol_columns + elif result_type=='optiflow': + mainresult_symbol_columns = optiflow_symbol_columns + + #Name columns if cols == 'None': try: df.columns = mainresult_symbol_columns[symbol] + ['Unit', 'Value'] - except KeyError: - print('Standard column format not found for this symbol') - elif type(cols) == list: - df.columns = cols + except ValueError: + try: + df.columns = mainresult_symbol_columns[symbol] + ['Value'] + except KeyError: + print('Standard column format not found for this symbol') + else: + df.columns = cols + + return df - def read_lines(name, file_path, make_space=True): if make_space: