From 71ec1a49d2486163a86760ae70b032a607c52178 Mon Sep 17 00:00:00 2001 From: killian-scalian Date: Thu, 9 Jan 2025 18:33:26 +0100 Subject: [PATCH 01/21] add load, solar and wind --- .../input_converter/src/converter.py | 78 +++++++++ src/andromede/input_converter/src/main.py | 151 ++++++++++++++++++ src/andromede/input_converter/src/utils.py | 64 ++++++++ .../antares_historic/antares_historic.yml | 4 +- tests/input_converter/test_converter.py | 81 +++++++++- tests/unittests/data/components.yml | 10 +- 6 files changed, 379 insertions(+), 9 deletions(-) create mode 100644 src/andromede/input_converter/src/main.py diff --git a/src/andromede/input_converter/src/converter.py b/src/andromede/input_converter/src/converter.py index ffc0aec2..40125e8a 100644 --- a/src/andromede/input_converter/src/converter.py +++ b/src/andromede/input_converter/src/converter.py @@ -162,6 +162,84 @@ def _convert_thermal_to_component_list( ) return components + def _convert_wind_matrix_to_component_list( + self, areas: list[Area] + ) -> list[InputComponent]: + components = [] + + for area in areas: + series_path = ( + self.study_path / "input" / "wind" / "series" / f"wind_{area.id}.txt" + ) + components.append( + InputComponent( + id=area.id, + model="wind", + parameters=[ + InputComponentParameter( + name="wind", + type="timeseries", + timeseries=str(series_path), + ) + ], + ) + ) + + return components + + def _convert_solar_matrix_to_component_list( + self, areas: list[Area] + ) -> list[InputComponent]: + components = [] + + for area in areas: + series_path = ( + self.study_path / "input" / "solar" / "series" / f"solar_{area.id}.txt" + ) + components.extend( + [ + InputComponent( + id=area.id, + model="solar", + parameters=[ + InputComponentParameter( + name="solar", + type="timeseries", + timeseries=str(series_path), + ) + ], + ) + ] + ) + + return components + + def _convert_load_matrix_to_component_list( + self, areas: list[Area] + ) -> list[InputComponent]: + components = [] + for area in areas: + series_path = ( + self.study_path / "input" / "load" / "series" / f"load_{area.id}.txt" + ) + components.extend( + [ + InputComponent( + id=area.id, + model="load", + parameters=[ + InputComponentParameter( + name="load", + type="timeseries", + timeseries=str(series_path), + ) + ], + ) + ] + ) + + return components + def convert_study_to_input_study(self) -> InputStudy: areas = self.study.read_areas() area_components = self._convert_area_to_component_list(areas) diff --git a/src/andromede/input_converter/src/main.py b/src/andromede/input_converter/src/main.py new file mode 100644 index 00000000..77c986b4 --- /dev/null +++ b/src/andromede/input_converter/src/main.py @@ -0,0 +1,151 @@ +from argparse import ArgumentParser, Namespace, ArgumentTypeError +from configparser import ConfigParser +import os +import sys +from pathlib import Path +from __init__ import __version__ +from converter import StudyConverter + +DEFAULT: dict = {} + + +class PathType: + """file or directory path type for `argparse` parser + + The `PathType` class represents a type of argument that can be used + with the `argparse` library. + This class takes three boolean arguments, `exists`, `file_ok`, and `dir_ok`, + which specify whether the path argument must exist, whether it can be a file, + and whether it can be a directory, respectively. + + Example Usage:: + + import argparse + from antarest.main import PathType + + parser = argparse.ArgumentParser() + parser.add_argument("--input", type=PathType(file_ok=True, exists=True)) + args = parser.parse_args() + + print(args.input) + + In the above example, `PathType` is used to specify the type of the `--input` + argument for the `argparse` parser. The argument must be an existing file path. + If the given path is not an existing file, the argparse library raises an error. + The Path object representing the given path is then printed to the console. + """ + + def __init__( + self, + exists: bool = False, + file_ok: bool = False, + dir_ok: bool = False, + ) -> None: + if not (file_ok or dir_ok): + msg = "Either `file_ok` or `dir_ok` must be set at a minimum." + raise ValueError(msg) + self.exists = exists + self.file_ok = file_ok + self.dir_ok = dir_ok + + def __call__(self, string: str) -> Path: + """ + Check whether the given string represents a valid path. + + If `exists` is `False`, the method simply returns the given path. + If `exists` is True, it checks whether the path exists and whether it is + a file or a directory, depending on the values of `file_ok` and `dir_ok`. + If the path exists and is of the correct type, the method returns the path; + otherwise, it raises an :class:`argparse.ArgumentTypeError` with an + appropriate error message. + + Args: + string: file or directory path + + Returns: + the file or directory path + + Raises + argparse.ArgumentTypeError: if the path is invalid + """ + file_path = Path(string).expanduser() + if not self.exists: + return file_path + if self.file_ok and self.dir_ok: + if file_path.exists(): + return file_path + msg = f"The file or directory path does not exist: '{file_path}'" + raise ArgumentTypeError(msg) + elif self.file_ok: + if file_path.is_file(): + return file_path + elif file_path.exists(): + msg = f"The path is not a regular file: '{file_path}'" + else: + msg = f"The file path does not exist: '{file_path}'" + raise ArgumentTypeError(msg) + elif self.dir_ok: + if file_path.is_dir(): + return file_path + elif file_path.exists(): + msg = f"The path is not a directory: '{file_path}'" + else: + msg = f"The directory path does not exist: '{file_path}'" + raise ArgumentTypeError(msg) + else: # pragma: no cover + raise NotImplementedError((self.file_ok, self.dir_ok)) + + +def handle_env(parser: ConfigParser) -> dict: + """Read configuration items from the config parser and set them as environment variables. + Return a dictionary of the environment variables that were set.""" + config_env = {} + for i, j in parser.items(): + for k, value in parser.items(i): + env_name = i + "_" + k + if not os.environ.get(env_name): + os.environ[env_name] = value + config_env.update({env_name: value}) + else: + config_env.update({env_name: os.environ.get(env_name, "")}) + return config_env + + +def parse_commandline() -> Namespace: + """Parse command-line arguments using argparse to specify configuration file paths, + logging options, and version display. Returns the parsed arguments.""" + parser = ArgumentParser() + parser.add_argument( + "-c", + "--conf", + type=PathType(exists=True, file_ok=True), + default="../data/config.ini", + ) + parser.add_argument( + "-v", + "--version", + action="version", + help="Display the server version and exit", + version=__version__, + ) + + return parser.parse_args() + + +if __name__ == "__main__": + config: dict = {} + args = parse_commandline() + config_parser = ConfigParser() + + # Load the default configuration dictionary into the config parser. + config_parser.read_dict(DEFAULT) + if args.conf: + # Check if the specified config file exists, if not, exit with an error message. + if not os.path.exists(args.conf): + sys.exit(f"Aborting: missing config file at {args.conf}") + else: + os.environ["CONFIG"] = str(os.path.abspath(args.conf)) + config_parser.read(args.conf) + + env_cfg = handle_env(config_parser) + converter = StudyConverter() diff --git a/src/andromede/input_converter/src/utils.py b/src/andromede/input_converter/src/utils.py index 3afcfcc7..339fb420 100644 --- a/src/andromede/input_converter/src/utils.py +++ b/src/andromede/input_converter/src/utils.py @@ -1,8 +1,11 @@ from pathlib import Path import yaml +from antares.craft.model.area import Area from pydantic import BaseModel +from andromede.study.parsing import InputComponent, InputComponentParameter + def resolve_path(path_str: Path) -> Path: path = Path(path_str) @@ -20,3 +23,64 @@ def transform_to_yaml(model: BaseModel, output_path: str) -> None: yaml_file, allow_unicode=True, ) + + +def convert_hydro_to_component_list(area: Area) -> list[InputComponent]: + raise NotImplementedError + + +# def convert_st_storages_to_component_list(area: Area) -> list[InputComponent]: +# raise NotImplementedError + + + + +def convert_misc_gen_to_component_list( + areas: list[Area], root_path: Path +) -> list[InputComponent]: + components = [] + + for area in areas: + components.extend( + [ + InputComponent( + id=area.id, + model="misc_gen", + parameters=[ + InputComponentParameter( + name=f"{area.id}_misc_gen", + type="timeseries", + timeseries=str(area.get_misc_gen_matrix()), + ) + ], + ) + ] + ) + + return components + + +def convert_reserves_matrix_to_component_list( + areas: list[Area], root_path: Path +) -> list[InputComponent]: + components = [] + + for area in areas: + components.extend( + [ + InputComponent( + id=area.id, + model="reserves", + parameters=[ + InputComponentParameter( + name=f"{area.id}_reserves", + type="timeseries", + timeseries=str(area.get_reserves_matrix()), + ) + ], + ) + ] + ) + + return components + diff --git a/src/andromede/libs/antares_historic/antares_historic.yml b/src/andromede/libs/antares_historic/antares_historic.yml index 3b1fd357..2ad4fc5d 100644 --- a/src/andromede/libs/antares_historic/antares_historic.yml +++ b/src/andromede/libs/antares_historic/antares_historic.yml @@ -124,10 +124,10 @@ library: - name: d_min_down type: integer scenario-dependent: false - - name: nb_units_min # Equals to ceil(p_min_cluster/p_max_unit), to be done in preprocessing + - name: nb_units_min # Equals to ceil(p_min_cluster/p_max_unit), to be done in preprocessing (in timeseries) type: integer scenario-dependent: false - - name: nb_units_max # Equals to ceil(p_max_cluster/p_max_unit), to be done in preprocessing + - name: nb_units_max # Equals to ceil(p_max_cluster/p_max_unit), to be done in preprocessing (in timeseries) type: integer variables: - name: generation diff --git a/tests/input_converter/test_converter.py b/tests/input_converter/test_converter.py index 2509c590..45c4cfe8 100644 --- a/tests/input_converter/test_converter.py +++ b/tests/input_converter/test_converter.py @@ -226,7 +226,7 @@ def test_convert_area_to_component(self, local_study_w_areas): area_components.sort(key=lambda x: x.id) assert area_components == expected_area_components - def test_convert_renewables_to_input_study(self, local_study_with_renewable): + def test_convert_renewables_to_component(self, local_study_with_renewable): areas, converter = self._init_area_reading(local_study_with_renewable) study_path = converter.study_path renewables_components = converter._convert_renewable_to_component_list(areas) @@ -272,7 +272,7 @@ def test_convert_renewables_to_input_study(self, local_study_with_renewable): ] assert renewables_components == expected_renewable_component - def test_convert_thermals_to_input_study(self, local_study_w_thermal): + def test_convert_thermals_to_component(self, local_study_w_thermal): areas, converter = self._init_area_reading(local_study_w_thermal) thermals_components = converter._convert_thermal_to_component_list(areas) @@ -406,3 +406,80 @@ def test_convert_area_to_yaml(self, local_study_w_areas): expected_validated_data.nodes.sort(key=lambda x: x.id) validated_data.nodes.sort(key=lambda x: x.id) assert validated_data == expected_validated_data + + def test_convert_wind_to_component(self, local_study_w_areas, fr_wind): + areas, converter = self._init_area_reading(local_study_w_areas) + + wind_components = converter._convert_wind_matrix_to_component_list(areas) + study_path = converter.study_path + + wind_timeserie = str(study_path / "input" / "wind" / "series" / f"wind_fr.txt") + expected_wind_components = InputComponent( + id="fr", + model="wind", + scenario_group=None, + parameters=[ + InputComponentParameter( + name="wind", + type="timeseries", + scenario_group=None, + value=None, + timeseries=f"{wind_timeserie}", + ), + ], + ) + + wind_components.sort(key=lambda x: x.id) + assert wind_components[1] == expected_wind_components + + def test_convert_solar_to_component(self, local_study_w_areas, fr_solar): + areas, converter = self._init_area_reading(local_study_w_areas) + + solar_components = converter._convert_solar_matrix_to_component_list(areas) + study_path = converter.study_path + + solar_timeserie = str( + study_path / "input" / "solar" / "series" / f"solar_fr.txt" + ) + expected_solar_components = InputComponent( + id="fr", + model="solar", + scenario_group=None, + parameters=[ + InputComponentParameter( + name="solar", + type="timeseries", + scenario_group=None, + value=None, + timeseries=f"{solar_timeserie}", + ), + ], + ) + + solar_components.sort(key=lambda x: x.id) + assert solar_components[1] == expected_solar_components + + def test_convert_load_to_component(self, local_study_w_areas, fr_load): + areas, converter = self._init_area_reading(local_study_w_areas) + + load_components = converter._convert_load_matrix_to_component_list(areas) + study_path = converter.study_path + + load_timeserie = str(study_path / "input" / "load" / "series" / f"load_fr.txt") + expected_load_components = InputComponent( + id="fr", + model="load", + scenario_group=None, + parameters=[ + InputComponentParameter( + name="load", + type="timeseries", + scenario_group=None, + value=None, + timeseries=f"{load_timeserie}", + ), + ], + ) + + load_components.sort(key=lambda x: x.id) + assert load_components[1] == expected_load_components diff --git a/tests/unittests/data/components.yml b/tests/unittests/data/components.yml index b5ae7570..f89275f5 100644 --- a/tests/unittests/data/components.yml +++ b/tests/unittests/data/components.yml @@ -32,14 +32,14 @@ study: value: 100 connections: - - component1: N + - component1: N # renewable id 1 port_1: injection_port - component2: D - port_2: injection_port + component2: D # area id 1 + port_2: injection_port - - component1: N + - component1: N # load id 2 port_1: injection_port - component2: G + component2: G # area id 2 port_2: injection_port From 7ed221b7d021c1db0b384f76f340294d96035295 Mon Sep 17 00:00:00 2001 From: killian-scalian Date: Fri, 10 Jan 2025 10:44:57 +0100 Subject: [PATCH 02/21] last changes of syntax, and add path verification --- .../input_converter/src/converter.py | 133 +++++++++++------- tests/input_converter/test_converter.py | 27 ++-- 2 files changed, 91 insertions(+), 69 deletions(-) diff --git a/src/andromede/input_converter/src/converter.py b/src/andromede/input_converter/src/converter.py index 40125e8a..b3208cd5 100644 --- a/src/andromede/input_converter/src/converter.py +++ b/src/andromede/input_converter/src/converter.py @@ -108,6 +108,7 @@ def _convert_thermal_to_component_list( for area in areas: thermals = area.read_thermal_clusters() for thermal in thermals: + # TODO tous les objets thermal ici sont connectés à l'area area.id series_path = ( self.study_path / "input" @@ -162,81 +163,106 @@ def _convert_thermal_to_component_list( ) return components - def _convert_wind_matrix_to_component_list( + def _convert_wind_to_component_list( self, areas: list[Area] ) -> list[InputComponent]: components = [] for area in areas: - series_path = ( - self.study_path / "input" / "wind" / "series" / f"wind_{area.id}.txt" - ) - components.append( - InputComponent( - id=area.id, - model="wind", - parameters=[ - InputComponentParameter( - name="wind", - type="timeseries", - timeseries=str(series_path), + try: + if area.get_wind_matrix().any: + series_path = ( + self.study_path + / "input" + / "wind" + / "series" + / f"wind_{area.id}.txt" + ) + + components.append( + InputComponent( + id=area.id, + model="wind", + parameters=[ + InputComponentParameter( + name="wind", + type="timeseries", + timeseries=str(series_path), + ) + ], ) - ], - ) - ) + ) + except FileNotFoundError: + pass return components - def _convert_solar_matrix_to_component_list( + def _convert_solar_to_component_list( self, areas: list[Area] ) -> list[InputComponent]: components = [] for area in areas: - series_path = ( - self.study_path / "input" / "solar" / "series" / f"solar_{area.id}.txt" - ) - components.extend( - [ - InputComponent( - id=area.id, - model="solar", - parameters=[ - InputComponentParameter( - name="solar", - type="timeseries", - timeseries=str(series_path), + try: + if area.get_solar_matrix().any: + series_path = ( + self.study_path + / "input" + / "solar" + / "series" + / f"solar_{area.id}.txt" + ) + components.extend( + [ + InputComponent( + id=area.id, + model="solar", + parameters=[ + InputComponentParameter( + name="solar", + type="timeseries", + timeseries=str(series_path), + ) + ], ) - ], + ] ) - ] - ) + except FileNotFoundError: + pass return components - def _convert_load_matrix_to_component_list( + def _convert_load_to_component_list( self, areas: list[Area] ) -> list[InputComponent]: components = [] for area in areas: - series_path = ( - self.study_path / "input" / "load" / "series" / f"load_{area.id}.txt" - ) - components.extend( - [ - InputComponent( - id=area.id, - model="load", - parameters=[ - InputComponentParameter( - name="load", - type="timeseries", - timeseries=str(series_path), + try: + if area.get_load_matrix().any: + series_path = ( + self.study_path + / "input" + / "load" + / "series" + / f"load_{area.id}.txt" + ) + components.extend( + [ + InputComponent( + id=area.id, + model="load", + parameters=[ + InputComponentParameter( + name="load", + type="timeseries", + timeseries=str(series_path), + ) + ], ) - ], + ] ) - ] - ) + except FileNotFoundError: + pass return components @@ -246,11 +272,10 @@ def convert_study_to_input_study(self) -> InputStudy: list_components = [] list_components.extend(self._convert_renewable_to_component_list(areas)) list_components.extend(self._convert_thermal_to_component_list(areas)) - # loads = convert_load_matrix_to_component_list(areas, root_path) + list_components.extend(self._convert_load_to_component_list(areas)) + list_components.extend(self._convert_wind_to_component_list(areas)) + list_components.extend(self._convert_solar_to_component_list(areas)) - # winds = convert_wind_matrix_to_component_list(areas, root_path) - # solars = convert_solar_matrix_to_component_list(areas, root_path) - # misc_gens = convert_misc_gen_to_component_list(areas, root_path) return InputStudy(nodes=area_components, components=list_components) def process_all(self) -> None: diff --git a/tests/input_converter/test_converter.py b/tests/input_converter/test_converter.py index 45c4cfe8..a58607d9 100644 --- a/tests/input_converter/test_converter.py +++ b/tests/input_converter/test_converter.py @@ -410,10 +410,10 @@ def test_convert_area_to_yaml(self, local_study_w_areas): def test_convert_wind_to_component(self, local_study_w_areas, fr_wind): areas, converter = self._init_area_reading(local_study_w_areas) - wind_components = converter._convert_wind_matrix_to_component_list(areas) + wind_components = converter._convert_wind_to_component_list(areas) study_path = converter.study_path - wind_timeserie = str(study_path / "input" / "wind" / "series" / f"wind_fr.txt") + wind_timeseries = str(study_path / "input" / "wind" / "series" / f"wind_fr.txt") expected_wind_components = InputComponent( id="fr", model="wind", @@ -424,21 +424,20 @@ def test_convert_wind_to_component(self, local_study_w_areas, fr_wind): type="timeseries", scenario_group=None, value=None, - timeseries=f"{wind_timeserie}", + timeseries=f"{wind_timeseries}", ), ], ) - wind_components.sort(key=lambda x: x.id) - assert wind_components[1] == expected_wind_components + assert wind_components[0] == expected_wind_components def test_convert_solar_to_component(self, local_study_w_areas, fr_solar): areas, converter = self._init_area_reading(local_study_w_areas) - solar_components = converter._convert_solar_matrix_to_component_list(areas) + solar_components = converter._convert_solar_to_component_list(areas) study_path = converter.study_path - solar_timeserie = str( + solar_timeseries = str( study_path / "input" / "solar" / "series" / f"solar_fr.txt" ) expected_solar_components = InputComponent( @@ -451,21 +450,20 @@ def test_convert_solar_to_component(self, local_study_w_areas, fr_solar): type="timeseries", scenario_group=None, value=None, - timeseries=f"{solar_timeserie}", + timeseries=f"{solar_timeseries}", ), ], ) - solar_components.sort(key=lambda x: x.id) - assert solar_components[1] == expected_solar_components + assert solar_components[0] == expected_solar_components def test_convert_load_to_component(self, local_study_w_areas, fr_load): areas, converter = self._init_area_reading(local_study_w_areas) - load_components = converter._convert_load_matrix_to_component_list(areas) + load_components = converter._convert_load_to_component_list(areas) study_path = converter.study_path - load_timeserie = str(study_path / "input" / "load" / "series" / f"load_fr.txt") + load_timeseries = str(study_path / "input" / "load" / "series" / f"load_fr.txt") expected_load_components = InputComponent( id="fr", model="load", @@ -476,10 +474,9 @@ def test_convert_load_to_component(self, local_study_w_areas, fr_load): type="timeseries", scenario_group=None, value=None, - timeseries=f"{load_timeserie}", + timeseries=f"{load_timeseries}", ), ], ) - load_components.sort(key=lambda x: x.id) - assert load_components[1] == expected_load_components + assert load_components[0] == expected_load_components From b0ea55fbd4a7dc2f445b479ecb203ae80db0c894 Mon Sep 17 00:00:00 2001 From: killian-scalian Date: Fri, 10 Jan 2025 10:49:49 +0100 Subject: [PATCH 03/21] dev traces --- src/andromede/input_converter/src/main.py | 151 ------------------ src/andromede/input_converter/src/utils.py | 64 -------- .../antares_historic/antares_historic.yml | 4 +- tests/unittests/data/components.yml | 11 +- .../components_for_short_term_storage.yml | 8 +- 5 files changed, 11 insertions(+), 227 deletions(-) delete mode 100644 src/andromede/input_converter/src/main.py diff --git a/src/andromede/input_converter/src/main.py b/src/andromede/input_converter/src/main.py deleted file mode 100644 index 77c986b4..00000000 --- a/src/andromede/input_converter/src/main.py +++ /dev/null @@ -1,151 +0,0 @@ -from argparse import ArgumentParser, Namespace, ArgumentTypeError -from configparser import ConfigParser -import os -import sys -from pathlib import Path -from __init__ import __version__ -from converter import StudyConverter - -DEFAULT: dict = {} - - -class PathType: - """file or directory path type for `argparse` parser - - The `PathType` class represents a type of argument that can be used - with the `argparse` library. - This class takes three boolean arguments, `exists`, `file_ok`, and `dir_ok`, - which specify whether the path argument must exist, whether it can be a file, - and whether it can be a directory, respectively. - - Example Usage:: - - import argparse - from antarest.main import PathType - - parser = argparse.ArgumentParser() - parser.add_argument("--input", type=PathType(file_ok=True, exists=True)) - args = parser.parse_args() - - print(args.input) - - In the above example, `PathType` is used to specify the type of the `--input` - argument for the `argparse` parser. The argument must be an existing file path. - If the given path is not an existing file, the argparse library raises an error. - The Path object representing the given path is then printed to the console. - """ - - def __init__( - self, - exists: bool = False, - file_ok: bool = False, - dir_ok: bool = False, - ) -> None: - if not (file_ok or dir_ok): - msg = "Either `file_ok` or `dir_ok` must be set at a minimum." - raise ValueError(msg) - self.exists = exists - self.file_ok = file_ok - self.dir_ok = dir_ok - - def __call__(self, string: str) -> Path: - """ - Check whether the given string represents a valid path. - - If `exists` is `False`, the method simply returns the given path. - If `exists` is True, it checks whether the path exists and whether it is - a file or a directory, depending on the values of `file_ok` and `dir_ok`. - If the path exists and is of the correct type, the method returns the path; - otherwise, it raises an :class:`argparse.ArgumentTypeError` with an - appropriate error message. - - Args: - string: file or directory path - - Returns: - the file or directory path - - Raises - argparse.ArgumentTypeError: if the path is invalid - """ - file_path = Path(string).expanduser() - if not self.exists: - return file_path - if self.file_ok and self.dir_ok: - if file_path.exists(): - return file_path - msg = f"The file or directory path does not exist: '{file_path}'" - raise ArgumentTypeError(msg) - elif self.file_ok: - if file_path.is_file(): - return file_path - elif file_path.exists(): - msg = f"The path is not a regular file: '{file_path}'" - else: - msg = f"The file path does not exist: '{file_path}'" - raise ArgumentTypeError(msg) - elif self.dir_ok: - if file_path.is_dir(): - return file_path - elif file_path.exists(): - msg = f"The path is not a directory: '{file_path}'" - else: - msg = f"The directory path does not exist: '{file_path}'" - raise ArgumentTypeError(msg) - else: # pragma: no cover - raise NotImplementedError((self.file_ok, self.dir_ok)) - - -def handle_env(parser: ConfigParser) -> dict: - """Read configuration items from the config parser and set them as environment variables. - Return a dictionary of the environment variables that were set.""" - config_env = {} - for i, j in parser.items(): - for k, value in parser.items(i): - env_name = i + "_" + k - if not os.environ.get(env_name): - os.environ[env_name] = value - config_env.update({env_name: value}) - else: - config_env.update({env_name: os.environ.get(env_name, "")}) - return config_env - - -def parse_commandline() -> Namespace: - """Parse command-line arguments using argparse to specify configuration file paths, - logging options, and version display. Returns the parsed arguments.""" - parser = ArgumentParser() - parser.add_argument( - "-c", - "--conf", - type=PathType(exists=True, file_ok=True), - default="../data/config.ini", - ) - parser.add_argument( - "-v", - "--version", - action="version", - help="Display the server version and exit", - version=__version__, - ) - - return parser.parse_args() - - -if __name__ == "__main__": - config: dict = {} - args = parse_commandline() - config_parser = ConfigParser() - - # Load the default configuration dictionary into the config parser. - config_parser.read_dict(DEFAULT) - if args.conf: - # Check if the specified config file exists, if not, exit with an error message. - if not os.path.exists(args.conf): - sys.exit(f"Aborting: missing config file at {args.conf}") - else: - os.environ["CONFIG"] = str(os.path.abspath(args.conf)) - config_parser.read(args.conf) - - env_cfg = handle_env(config_parser) - converter = StudyConverter() diff --git a/src/andromede/input_converter/src/utils.py b/src/andromede/input_converter/src/utils.py index 339fb420..3afcfcc7 100644 --- a/src/andromede/input_converter/src/utils.py +++ b/src/andromede/input_converter/src/utils.py @@ -1,11 +1,8 @@ from pathlib import Path import yaml -from antares.craft.model.area import Area from pydantic import BaseModel -from andromede.study.parsing import InputComponent, InputComponentParameter - def resolve_path(path_str: Path) -> Path: path = Path(path_str) @@ -23,64 +20,3 @@ def transform_to_yaml(model: BaseModel, output_path: str) -> None: yaml_file, allow_unicode=True, ) - - -def convert_hydro_to_component_list(area: Area) -> list[InputComponent]: - raise NotImplementedError - - -# def convert_st_storages_to_component_list(area: Area) -> list[InputComponent]: -# raise NotImplementedError - - - - -def convert_misc_gen_to_component_list( - areas: list[Area], root_path: Path -) -> list[InputComponent]: - components = [] - - for area in areas: - components.extend( - [ - InputComponent( - id=area.id, - model="misc_gen", - parameters=[ - InputComponentParameter( - name=f"{area.id}_misc_gen", - type="timeseries", - timeseries=str(area.get_misc_gen_matrix()), - ) - ], - ) - ] - ) - - return components - - -def convert_reserves_matrix_to_component_list( - areas: list[Area], root_path: Path -) -> list[InputComponent]: - components = [] - - for area in areas: - components.extend( - [ - InputComponent( - id=area.id, - model="reserves", - parameters=[ - InputComponentParameter( - name=f"{area.id}_reserves", - type="timeseries", - timeseries=str(area.get_reserves_matrix()), - ) - ], - ) - ] - ) - - return components - diff --git a/src/andromede/libs/antares_historic/antares_historic.yml b/src/andromede/libs/antares_historic/antares_historic.yml index 2ad4fc5d..3b1fd357 100644 --- a/src/andromede/libs/antares_historic/antares_historic.yml +++ b/src/andromede/libs/antares_historic/antares_historic.yml @@ -124,10 +124,10 @@ library: - name: d_min_down type: integer scenario-dependent: false - - name: nb_units_min # Equals to ceil(p_min_cluster/p_max_unit), to be done in preprocessing (in timeseries) + - name: nb_units_min # Equals to ceil(p_min_cluster/p_max_unit), to be done in preprocessing type: integer scenario-dependent: false - - name: nb_units_max # Equals to ceil(p_max_cluster/p_max_unit), to be done in preprocessing (in timeseries) + - name: nb_units_max # Equals to ceil(p_max_cluster/p_max_unit), to be done in preprocessing type: integer variables: - name: generation diff --git a/tests/unittests/data/components.yml b/tests/unittests/data/components.yml index f89275f5..ab0be1b5 100644 --- a/tests/unittests/data/components.yml +++ b/tests/unittests/data/components.yml @@ -32,15 +32,14 @@ study: value: 100 connections: - - component1: N # renewable id 1 + - component1: N port_1: injection_port - component2: D # area id 1 - port_2: injection_port + component2: D + port_2: injection_port - - component1: N # load id 2 + - component1: N port_1: injection_port - component2: G # area id 2 + component2: G port_2: injection_port - diff --git a/tests/unittests/data/components_for_short_term_storage.yml b/tests/unittests/data/components_for_short_term_storage.yml index d63f12a3..45013178 100644 --- a/tests/unittests/data/components_for_short_term_storage.yml +++ b/tests/unittests/data/components_for_short_term_storage.yml @@ -57,10 +57,10 @@ study: connections: - - component1: N - port_1: injection_port - component2: D - port_2: injection_port + - component1: N # thermal.id + port_1: injection_port # balance_port + component2: D # area.id + port_2: injection_port # balance_port - component1: N port_1: injection_port From 99a878193d7b8dfc077d7dedcbcca69788b8f802 Mon Sep 17 00:00:00 2001 From: killian-scalian Date: Fri, 10 Jan 2025 10:55:57 +0100 Subject: [PATCH 04/21] area.get_wind_matrix() is just here to check to absence or not of the file --- .../input_converter/src/converter.py | 132 +++++++++--------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/src/andromede/input_converter/src/converter.py b/src/andromede/input_converter/src/converter.py index b3208cd5..0b91b737 100644 --- a/src/andromede/input_converter/src/converter.py +++ b/src/andromede/input_converter/src/converter.py @@ -170,28 +170,28 @@ def _convert_wind_to_component_list( for area in areas: try: - if area.get_wind_matrix().any: - series_path = ( - self.study_path - / "input" - / "wind" - / "series" - / f"wind_{area.id}.txt" - ) + area.get_wind_matrix() + series_path = ( + self.study_path + / "input" + / "wind" + / "series" + / f"wind_{area.id}.txt" + ) - components.append( - InputComponent( - id=area.id, - model="wind", - parameters=[ - InputComponentParameter( - name="wind", - type="timeseries", - timeseries=str(series_path), - ) - ], - ) + components.append( + InputComponent( + id=area.id, + model="wind", + parameters=[ + InputComponentParameter( + name="wind", + type="timeseries", + timeseries=str(series_path), + ) + ], ) + ) except FileNotFoundError: pass @@ -204,29 +204,29 @@ def _convert_solar_to_component_list( for area in areas: try: - if area.get_solar_matrix().any: - series_path = ( - self.study_path - / "input" - / "solar" - / "series" - / f"solar_{area.id}.txt" - ) - components.extend( - [ - InputComponent( - id=area.id, - model="solar", - parameters=[ - InputComponentParameter( - name="solar", - type="timeseries", - timeseries=str(series_path), - ) - ], - ) - ] - ) + area.get_solar_matrix() + series_path = ( + self.study_path + / "input" + / "solar" + / "series" + / f"solar_{area.id}.txt" + ) + components.extend( + [ + InputComponent( + id=area.id, + model="solar", + parameters=[ + InputComponentParameter( + name="solar", + type="timeseries", + timeseries=str(series_path), + ) + ], + ) + ] + ) except FileNotFoundError: pass @@ -238,29 +238,29 @@ def _convert_load_to_component_list( components = [] for area in areas: try: - if area.get_load_matrix().any: - series_path = ( - self.study_path - / "input" - / "load" - / "series" - / f"load_{area.id}.txt" - ) - components.extend( - [ - InputComponent( - id=area.id, - model="load", - parameters=[ - InputComponentParameter( - name="load", - type="timeseries", - timeseries=str(series_path), - ) - ], - ) - ] - ) + area.get_load_matrix() + series_path = ( + self.study_path + / "input" + / "load" + / "series" + / f"load_{area.id}.txt" + ) + components.extend( + [ + InputComponent( + id=area.id, + model="load", + parameters=[ + InputComponentParameter( + name="load", + type="timeseries", + timeseries=str(series_path), + ) + ], + ) + ] + ) except FileNotFoundError: pass From 2cbf2c5a0dd9a80a2f8cd64fb35cfc972e903a06 Mon Sep 17 00:00:00 2001 From: killian-scalian Date: Fri, 10 Jan 2025 11:00:37 +0100 Subject: [PATCH 05/21] remove todo --- src/andromede/input_converter/src/converter.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/andromede/input_converter/src/converter.py b/src/andromede/input_converter/src/converter.py index 0b91b737..ead7a410 100644 --- a/src/andromede/input_converter/src/converter.py +++ b/src/andromede/input_converter/src/converter.py @@ -108,7 +108,6 @@ def _convert_thermal_to_component_list( for area in areas: thermals = area.read_thermal_clusters() for thermal in thermals: - # TODO tous les objets thermal ici sont connectés à l'area area.id series_path = ( self.study_path / "input" From b5e58221cf1e46d78908cab4c1cc5fecd7ff3a24 Mon Sep 17 00:00:00 2001 From: killian-scalian Date: Fri, 10 Jan 2025 11:06:32 +0100 Subject: [PATCH 06/21] dev traces --- tests/unittests/data/components.yml | 2 -- .../unittests/data/components_for_short_term_storage.yml | 8 ++++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/unittests/data/components.yml b/tests/unittests/data/components.yml index ab0be1b5..6915ea3a 100644 --- a/tests/unittests/data/components.yml +++ b/tests/unittests/data/components.yml @@ -41,5 +41,3 @@ study: port_1: injection_port component2: G port_2: injection_port - - diff --git a/tests/unittests/data/components_for_short_term_storage.yml b/tests/unittests/data/components_for_short_term_storage.yml index 45013178..d63f12a3 100644 --- a/tests/unittests/data/components_for_short_term_storage.yml +++ b/tests/unittests/data/components_for_short_term_storage.yml @@ -57,10 +57,10 @@ study: connections: - - component1: N # thermal.id - port_1: injection_port # balance_port - component2: D # area.id - port_2: injection_port # balance_port + - component1: N + port_1: injection_port + component2: D + port_2: injection_port - component1: N port_1: injection_port From 267e4f6cfdef5685c3a91b6342ef59aba92dafa1 Mon Sep 17 00:00:00 2001 From: killian-scalian Date: Mon, 13 Jan 2025 10:52:56 +0100 Subject: [PATCH 07/21] add port connections --- .../input_converter/src/converter.py | 104 ++++++++++++++---- tests/input_converter/test_converter.py | 24 ++-- 2 files changed, 101 insertions(+), 27 deletions(-) diff --git a/src/andromede/input_converter/src/converter.py b/src/andromede/input_converter/src/converter.py index ead7a410..1ee8b913 100644 --- a/src/andromede/input_converter/src/converter.py +++ b/src/andromede/input_converter/src/converter.py @@ -16,7 +16,12 @@ from antares.craft.model.study import Study, read_study_local from andromede.input_converter.src.utils import resolve_path -from andromede.study.parsing import InputComponent, InputComponentParameter, InputStudy +from andromede.study.parsing import ( + InputComponent, + InputComponentParameter, + InputStudy, + InputPortConnections, +) class AntaresStudyConverter: @@ -60,8 +65,9 @@ def _convert_area_to_component_list( def _convert_renewable_to_component_list( self, areas: list[Area] - ) -> list[InputComponent]: + ) -> tuple[list[InputComponent], list[InputPortConnections]]: components = [] + connections = [] for area in areas: renewables = area.read_renewables() for renewable in renewables: @@ -97,13 +103,22 @@ def _convert_renewable_to_component_list( ], ) ) + connections.append( + InputPortConnections( + component1=renewable.id, + port_1="balance_port", + component2=area.id, + port_2="balance_port", + ) + ) - return components + return components, connections def _convert_thermal_to_component_list( self, areas: list[Area] - ) -> list[InputComponent]: + ) -> tuple[list[InputComponent], list[InputPortConnections]]: components = [] + connections = [] # Add thermal components for each area for area in areas: thermals = area.read_thermal_clusters() @@ -160,13 +175,21 @@ def _convert_thermal_to_component_list( ], ) ) - return components + connections.append( + InputPortConnections( + component1=thermal.id, + port_1="balance_port", + component2=area.id, + port_2="balance_port", + ) + ) + return components, connections def _convert_wind_to_component_list( self, areas: list[Area] - ) -> list[InputComponent]: + ) -> tuple[list[InputComponent], list[InputPortConnections]]: components = [] - + connections = [] for area in areas: try: area.get_wind_matrix() @@ -191,16 +214,24 @@ def _convert_wind_to_component_list( ], ) ) + connections.append( + InputPortConnections( + component1="wind", + port_1="balance_port", + component2=area.id, + port_2="balance_port", + ) + ) except FileNotFoundError: pass - return components + return components, connections def _convert_solar_to_component_list( self, areas: list[Area] - ) -> list[InputComponent]: + ) -> tuple[list[InputComponent], list[InputPortConnections]]: components = [] - + connections = [] for area in areas: try: area.get_solar_matrix() @@ -226,15 +257,24 @@ def _convert_solar_to_component_list( ) ] ) + connections.append( + InputPortConnections( + component1="solar", + port_1="balance_port", + component2=area.id, + port_2="balance_port", + ) + ) except FileNotFoundError: pass - return components + return components, connections def _convert_load_to_component_list( self, areas: list[Area] - ) -> list[InputComponent]: + ) -> tuple[list[InputComponent], list[InputPortConnections]]: components = [] + connections = [] for area in areas: try: area.get_load_matrix() @@ -260,22 +300,46 @@ def _convert_load_to_component_list( ) ] ) + connections.append( + InputPortConnections( + component1="load", + port_1="balance_port", + component2=area.id, + port_2="balance_port", + ) + ) except FileNotFoundError: pass - return components + return components, connections def convert_study_to_input_study(self) -> InputStudy: areas = self.study.read_areas() area_components = self._convert_area_to_component_list(areas) - list_components = [] - list_components.extend(self._convert_renewable_to_component_list(areas)) - list_components.extend(self._convert_thermal_to_component_list(areas)) - list_components.extend(self._convert_load_to_component_list(areas)) - list_components.extend(self._convert_wind_to_component_list(areas)) - list_components.extend(self._convert_solar_to_component_list(areas)) - return InputStudy(nodes=area_components, components=list_components) + conversion_methods = [ + self._convert_renewable_to_component_list, + self._convert_thermal_to_component_list, + self._convert_load_to_component_list, + self._convert_wind_to_component_list, + self._convert_solar_to_component_list, + ] + + list_components: list[InputComponent] = [] + list_connections: list[InputPortConnections] = [] + + for method in conversion_methods: + components, connections = method(areas) + if components: + list_components.extend(components) + if connections: + list_connections.extend(connections) + + return InputStudy( + nodes=area_components, + components=list_components, + connections=list_connections, + ) def process_all(self) -> None: raise NotImplementedError diff --git a/tests/input_converter/test_converter.py b/tests/input_converter/test_converter.py index a58607d9..99b086fc 100644 --- a/tests/input_converter/test_converter.py +++ b/tests/input_converter/test_converter.py @@ -15,6 +15,7 @@ from andromede.study.parsing import ( InputComponent, InputComponentParameter, + InputPortConnections, InputStudy, parse_yaml_components, ) @@ -161,7 +162,7 @@ def test_convert_study_to_input_study(self, local_study_w_thermal): ], ) ], - connections=[], + connections=[InputPortConnections(component1='gaz', port_1='balance_port', component2='fr', port_2='balance_port')], ) # To ensure that the comparison between the actual and expected results is not affected by the order of the nodes, @@ -169,7 +170,6 @@ def test_convert_study_to_input_study(self, local_study_w_thermal): # This sorting step ensures that the test checks only the presence and validity of the nodes, not their order. input_study.nodes.sort(key=lambda x: x.id) expected_input_study.nodes.sort(key=lambda x: x.id) - assert input_study == expected_input_study def test_convert_area_to_component(self, local_study_w_areas): @@ -229,7 +229,7 @@ def test_convert_area_to_component(self, local_study_w_areas): def test_convert_renewables_to_component(self, local_study_with_renewable): areas, converter = self._init_area_reading(local_study_with_renewable) study_path = converter.study_path - renewables_components = converter._convert_renewable_to_component_list(areas) + renewables_components, renewable_connections = converter._convert_renewable_to_component_list(areas) timeserie_path = str( study_path @@ -240,6 +240,7 @@ def test_convert_renewables_to_component(self, local_study_with_renewable): / "generation" / "series.txt" ) + expected_renewable_connections = [InputPortConnections(component1='generation', port_1='balance_port', component2='fr', port_2='balance_port')] expected_renewable_component = [ InputComponent( id="generation", @@ -271,16 +272,18 @@ def test_convert_renewables_to_component(self, local_study_with_renewable): ) ] assert renewables_components == expected_renewable_component + assert renewable_connections == expected_renewable_connections def test_convert_thermals_to_component(self, local_study_w_thermal): areas, converter = self._init_area_reading(local_study_w_thermal) - thermals_components = converter._convert_thermal_to_component_list(areas) + thermals_components, thermals_connections= converter._convert_thermal_to_component_list(areas) study_path = converter.study_path p_max_timeserie = str( study_path / "input" / "thermal" / "series" / "fr" / "gaz" / "series.txt" ) + expected_thermals_connections = [InputPortConnections(component1='gaz', port_1='balance_port', component2='fr', port_2='balance_port')] expected_thermals_components = [ InputComponent( id="gaz", @@ -340,6 +343,7 @@ def test_convert_thermals_to_component(self, local_study_w_thermal): ) ] assert thermals_components == expected_thermals_components + assert thermals_connections == expected_thermals_connections def test_convert_area_to_yaml(self, local_study_w_areas): areas, converter = self._init_area_reading(local_study_w_areas) @@ -410,10 +414,11 @@ def test_convert_area_to_yaml(self, local_study_w_areas): def test_convert_wind_to_component(self, local_study_w_areas, fr_wind): areas, converter = self._init_area_reading(local_study_w_areas) - wind_components = converter._convert_wind_to_component_list(areas) + wind_components, wind_connection = converter._convert_wind_to_component_list(areas) study_path = converter.study_path wind_timeseries = str(study_path / "input" / "wind" / "series" / f"wind_fr.txt") + expected_wind_connection = [InputPortConnections(component1='wind', port_1='balance_port', component2='fr', port_2='balance_port')] expected_wind_components = InputComponent( id="fr", model="wind", @@ -430,16 +435,18 @@ def test_convert_wind_to_component(self, local_study_w_areas, fr_wind): ) assert wind_components[0] == expected_wind_components + assert wind_connection == expected_wind_connection def test_convert_solar_to_component(self, local_study_w_areas, fr_solar): areas, converter = self._init_area_reading(local_study_w_areas) - solar_components = converter._convert_solar_to_component_list(areas) + solar_components, solar_connection = converter._convert_solar_to_component_list(areas) study_path = converter.study_path solar_timeseries = str( study_path / "input" / "solar" / "series" / f"solar_fr.txt" ) + expected_solar_connection = [InputPortConnections(component1='solar', port_1='balance_port', component2='fr', port_2='balance_port')] expected_solar_components = InputComponent( id="fr", model="solar", @@ -456,14 +463,16 @@ def test_convert_solar_to_component(self, local_study_w_areas, fr_solar): ) assert solar_components[0] == expected_solar_components + assert solar_connection == expected_solar_connection def test_convert_load_to_component(self, local_study_w_areas, fr_load): areas, converter = self._init_area_reading(local_study_w_areas) - load_components = converter._convert_load_to_component_list(areas) + load_components, load_connection = converter._convert_load_to_component_list(areas) study_path = converter.study_path load_timeseries = str(study_path / "input" / "load" / "series" / f"load_fr.txt") + expected_load_connection = [InputPortConnections(component1='load', port_1='balance_port', component2='fr', port_2='balance_port')] expected_load_components = InputComponent( id="fr", model="load", @@ -480,3 +489,4 @@ def test_convert_load_to_component(self, local_study_w_areas, fr_load): ) assert load_components[0] == expected_load_components + assert load_connection == expected_load_connection \ No newline at end of file From 0013411f480fa8c53259b3f79403fd61c42bb6be Mon Sep 17 00:00:00 2001 From: killian-scalian Date: Mon, 13 Jan 2025 10:54:41 +0100 Subject: [PATCH 08/21] lint --- tests/input_converter/test_converter.py | 78 +++++++++++++++++++++---- 1 file changed, 66 insertions(+), 12 deletions(-) diff --git a/tests/input_converter/test_converter.py b/tests/input_converter/test_converter.py index 99b086fc..01086447 100644 --- a/tests/input_converter/test_converter.py +++ b/tests/input_converter/test_converter.py @@ -162,7 +162,14 @@ def test_convert_study_to_input_study(self, local_study_w_thermal): ], ) ], - connections=[InputPortConnections(component1='gaz', port_1='balance_port', component2='fr', port_2='balance_port')], + connections=[ + InputPortConnections( + component1="gaz", + port_1="balance_port", + component2="fr", + port_2="balance_port", + ) + ], ) # To ensure that the comparison between the actual and expected results is not affected by the order of the nodes, @@ -229,7 +236,10 @@ def test_convert_area_to_component(self, local_study_w_areas): def test_convert_renewables_to_component(self, local_study_with_renewable): areas, converter = self._init_area_reading(local_study_with_renewable) study_path = converter.study_path - renewables_components, renewable_connections = converter._convert_renewable_to_component_list(areas) + ( + renewables_components, + renewable_connections, + ) = converter._convert_renewable_to_component_list(areas) timeserie_path = str( study_path @@ -240,7 +250,14 @@ def test_convert_renewables_to_component(self, local_study_with_renewable): / "generation" / "series.txt" ) - expected_renewable_connections = [InputPortConnections(component1='generation', port_1='balance_port', component2='fr', port_2='balance_port')] + expected_renewable_connections = [ + InputPortConnections( + component1="generation", + port_1="balance_port", + component2="fr", + port_2="balance_port", + ) + ] expected_renewable_component = [ InputComponent( id="generation", @@ -277,13 +294,23 @@ def test_convert_renewables_to_component(self, local_study_with_renewable): def test_convert_thermals_to_component(self, local_study_w_thermal): areas, converter = self._init_area_reading(local_study_w_thermal) - thermals_components, thermals_connections= converter._convert_thermal_to_component_list(areas) + ( + thermals_components, + thermals_connections, + ) = converter._convert_thermal_to_component_list(areas) study_path = converter.study_path p_max_timeserie = str( study_path / "input" / "thermal" / "series" / "fr" / "gaz" / "series.txt" ) - expected_thermals_connections = [InputPortConnections(component1='gaz', port_1='balance_port', component2='fr', port_2='balance_port')] + expected_thermals_connections = [ + InputPortConnections( + component1="gaz", + port_1="balance_port", + component2="fr", + port_2="balance_port", + ) + ] expected_thermals_components = [ InputComponent( id="gaz", @@ -414,11 +441,20 @@ def test_convert_area_to_yaml(self, local_study_w_areas): def test_convert_wind_to_component(self, local_study_w_areas, fr_wind): areas, converter = self._init_area_reading(local_study_w_areas) - wind_components, wind_connection = converter._convert_wind_to_component_list(areas) + wind_components, wind_connection = converter._convert_wind_to_component_list( + areas + ) study_path = converter.study_path wind_timeseries = str(study_path / "input" / "wind" / "series" / f"wind_fr.txt") - expected_wind_connection = [InputPortConnections(component1='wind', port_1='balance_port', component2='fr', port_2='balance_port')] + expected_wind_connection = [ + InputPortConnections( + component1="wind", + port_1="balance_port", + component2="fr", + port_2="balance_port", + ) + ] expected_wind_components = InputComponent( id="fr", model="wind", @@ -440,13 +476,22 @@ def test_convert_wind_to_component(self, local_study_w_areas, fr_wind): def test_convert_solar_to_component(self, local_study_w_areas, fr_solar): areas, converter = self._init_area_reading(local_study_w_areas) - solar_components, solar_connection = converter._convert_solar_to_component_list(areas) + solar_components, solar_connection = converter._convert_solar_to_component_list( + areas + ) study_path = converter.study_path solar_timeseries = str( study_path / "input" / "solar" / "series" / f"solar_fr.txt" ) - expected_solar_connection = [InputPortConnections(component1='solar', port_1='balance_port', component2='fr', port_2='balance_port')] + expected_solar_connection = [ + InputPortConnections( + component1="solar", + port_1="balance_port", + component2="fr", + port_2="balance_port", + ) + ] expected_solar_components = InputComponent( id="fr", model="solar", @@ -468,11 +513,20 @@ def test_convert_solar_to_component(self, local_study_w_areas, fr_solar): def test_convert_load_to_component(self, local_study_w_areas, fr_load): areas, converter = self._init_area_reading(local_study_w_areas) - load_components, load_connection = converter._convert_load_to_component_list(areas) + load_components, load_connection = converter._convert_load_to_component_list( + areas + ) study_path = converter.study_path load_timeseries = str(study_path / "input" / "load" / "series" / f"load_fr.txt") - expected_load_connection = [InputPortConnections(component1='load', port_1='balance_port', component2='fr', port_2='balance_port')] + expected_load_connection = [ + InputPortConnections( + component1="load", + port_1="balance_port", + component2="fr", + port_2="balance_port", + ) + ] expected_load_components = InputComponent( id="fr", model="load", @@ -489,4 +543,4 @@ def test_convert_load_to_component(self, local_study_w_areas, fr_load): ) assert load_components[0] == expected_load_components - assert load_connection == expected_load_connection \ No newline at end of file + assert load_connection == expected_load_connection From cceaa607c1966bfbbe7fd9ea850cab5600b99273 Mon Sep 17 00:00:00 2001 From: killian-scalian Date: Mon, 13 Jan 2025 14:27:43 +0100 Subject: [PATCH 09/21] add error message with print and reduce exception size --- .../input_converter/src/converter.py | 145 +++++++++--------- 1 file changed, 75 insertions(+), 70 deletions(-) diff --git a/src/andromede/input_converter/src/converter.py b/src/andromede/input_converter/src/converter.py index 1ee8b913..674e7dc0 100644 --- a/src/andromede/input_converter/src/converter.py +++ b/src/andromede/input_converter/src/converter.py @@ -192,7 +192,6 @@ def _convert_wind_to_component_list( connections = [] for area in areas: try: - area.get_wind_matrix() series_path = ( self.study_path / "input" @@ -200,30 +199,32 @@ def _convert_wind_to_component_list( / "series" / f"wind_{area.id}.txt" ) + area.get_wind_matrix() + except FileNotFoundError: + print(f"File {series_path} not found") + continue - components.append( - InputComponent( - id=area.id, - model="wind", - parameters=[ - InputComponentParameter( - name="wind", - type="timeseries", - timeseries=str(series_path), - ) - ], - ) + components.append( + InputComponent( + id=area.id, + model="wind", + parameters=[ + InputComponentParameter( + name="wind", + type="timeseries", + timeseries=str(series_path), + ) + ], ) - connections.append( - InputPortConnections( - component1="wind", - port_1="balance_port", - component2=area.id, - port_2="balance_port", - ) + ) + connections.append( + InputPortConnections( + component1="wind", + port_1="balance_port", + component2=area.id, + port_2="balance_port", ) - except FileNotFoundError: - pass + ) return components, connections @@ -234,7 +235,6 @@ def _convert_solar_to_component_list( connections = [] for area in areas: try: - area.get_solar_matrix() series_path = ( self.study_path / "input" @@ -242,31 +242,34 @@ def _convert_solar_to_component_list( / "series" / f"solar_{area.id}.txt" ) - components.extend( - [ - InputComponent( - id=area.id, - model="solar", - parameters=[ - InputComponentParameter( - name="solar", - type="timeseries", - timeseries=str(series_path), - ) - ], - ) - ] - ) - connections.append( - InputPortConnections( - component1="solar", - port_1="balance_port", - component2=area.id, - port_2="balance_port", + area.get_solar_matrix() + except FileNotFoundError: + print(f"File {series_path} not found") + continue + + components.extend( + [ + InputComponent( + id=area.id, + model="solar", + parameters=[ + InputComponentParameter( + name="solar", + type="timeseries", + timeseries=str(series_path), + ) + ], ) + ] + ) + connections.append( + InputPortConnections( + component1="solar", + port_1="balance_port", + component2=area.id, + port_2="balance_port", ) - except FileNotFoundError: - pass + ) return components, connections @@ -277,7 +280,6 @@ def _convert_load_to_component_list( connections = [] for area in areas: try: - area.get_load_matrix() series_path = ( self.study_path / "input" @@ -285,31 +287,34 @@ def _convert_load_to_component_list( / "series" / f"load_{area.id}.txt" ) - components.extend( - [ - InputComponent( - id=area.id, - model="load", - parameters=[ - InputComponentParameter( - name="load", - type="timeseries", - timeseries=str(series_path), - ) - ], - ) - ] - ) - connections.append( - InputPortConnections( - component1="load", - port_1="balance_port", - component2=area.id, - port_2="balance_port", + area.get_load_matrix() + except FileNotFoundError: + print(f"File {series_path} not found") + continue + + components.extend( + [ + InputComponent( + id=area.id, + model="load", + parameters=[ + InputComponentParameter( + name="load", + type="timeseries", + timeseries=str(series_path), + ) + ], ) + ] + ) + connections.append( + InputPortConnections( + component1="load", + port_1="balance_port", + component2=area.id, + port_2="balance_port", ) - except FileNotFoundError: - pass + ) return components, connections From 34e21866b88615b5b346e5c362ee8e43288390a6 Mon Sep 17 00:00:00 2001 From: killian-scalian Date: Mon, 13 Jan 2025 17:46:36 +0100 Subject: [PATCH 10/21] add verifications for presence of dataframe --- .../input_converter/src/converter.py | 193 +++++++++--------- tests/input_converter/conftest.py | 10 +- tests/input_converter/test_converter.py | 108 ++++++---- 3 files changed, 172 insertions(+), 139 deletions(-) diff --git a/src/andromede/input_converter/src/converter.py b/src/andromede/input_converter/src/converter.py index 674e7dc0..3dd2726c 100644 --- a/src/andromede/input_converter/src/converter.py +++ b/src/andromede/input_converter/src/converter.py @@ -38,6 +38,22 @@ def __init__(self, study_input: Union[Path, Study]): else: raise TypeError("Invalid input type") + def _validate_matrix(self, df): + """ + Check and validate the following conditions: + 1. The dataframe from this path is not empty. + 2. The dataframe does not contains only zero values. + + :param df: dataframe to validate. + """ + if df.empty: + return False + + if (df == 0).all().all(): + return False + + return True + def _convert_area_to_component_list( self, areas: list[Area] ) -> list[InputComponent]: @@ -191,40 +207,32 @@ def _convert_wind_to_component_list( components = [] connections = [] for area in areas: - try: - series_path = ( - self.study_path - / "input" - / "wind" - / "series" - / f"wind_{area.id}.txt" - ) - area.get_wind_matrix() - except FileNotFoundError: - print(f"File {series_path} not found") - continue - - components.append( - InputComponent( - id=area.id, - model="wind", - parameters=[ - InputComponentParameter( - name="wind", - type="timeseries", - timeseries=str(series_path), - ) - ], - ) - ) - connections.append( - InputPortConnections( - component1="wind", - port_1="balance_port", - component2=area.id, - port_2="balance_port", - ) + series_path = ( + self.study_path / "input" / "wind" / "series" / f"wind_{area.id}.txt" ) + if series_path.exists(): + if self._validate_matrix(area.get_wind_matrix()): + components.append( + InputComponent( + id=area.id, + model="wind", + parameters=[ + InputComponentParameter( + name="wind", + type="timeseries", + timeseries=str(series_path), + ) + ], + ) + ) + connections.append( + InputPortConnections( + component1="wind", + port_1="balance_port", + component2=area.id, + port_2="balance_port", + ) + ) return components, connections @@ -234,42 +242,35 @@ def _convert_solar_to_component_list( components = [] connections = [] for area in areas: - try: - series_path = ( - self.study_path - / "input" - / "solar" - / "series" - / f"solar_{area.id}.txt" - ) - area.get_solar_matrix() - except FileNotFoundError: - print(f"File {series_path} not found") - continue + series_path = ( + self.study_path / "input" / "solar" / "series" / f"solar_{area.id}.txt" + ) - components.extend( - [ - InputComponent( - id=area.id, - model="solar", - parameters=[ - InputComponentParameter( - name="solar", - type="timeseries", - timeseries=str(series_path), + if series_path.exists(): + if self._validate_matrix(area.get_solar_matrix()): + components.extend( + [ + InputComponent( + id=area.id, + model="solar", + parameters=[ + InputComponentParameter( + name="solar", + type="timeseries", + timeseries=str(series_path), + ) + ], ) - ], + ] + ) + connections.append( + InputPortConnections( + component1="solar", + port_1="balance_port", + component2=area.id, + port_2="balance_port", + ) ) - ] - ) - connections.append( - InputPortConnections( - component1="solar", - port_1="balance_port", - component2=area.id, - port_2="balance_port", - ) - ) return components, connections @@ -279,42 +280,34 @@ def _convert_load_to_component_list( components = [] connections = [] for area in areas: - try: - series_path = ( - self.study_path - / "input" - / "load" - / "series" - / f"load_{area.id}.txt" - ) - area.get_load_matrix() - except FileNotFoundError: - print(f"File {series_path} not found") - continue - - components.extend( - [ - InputComponent( - id=area.id, - model="load", - parameters=[ - InputComponentParameter( - name="load", - type="timeseries", - timeseries=str(series_path), + series_path = ( + self.study_path / "input" / "load" / "series" / f"load_{area.id}.txt" + ) + if series_path.exists(): + if self._validate_matrix(area.get_load_matrix()): + components.extend( + [ + InputComponent( + id=area.id, + model="load", + parameters=[ + InputComponentParameter( + name="load", + type="timeseries", + timeseries=str(series_path), + ) + ], ) - ], + ] + ) + connections.append( + InputPortConnections( + component1="load", + port_1="balance_port", + component2=area.id, + port_2="balance_port", + ) ) - ] - ) - connections.append( - InputPortConnections( - component1="load", - port_1="balance_port", - component2=area.id, - port_2="balance_port", - ) - ) return components, connections diff --git a/tests/input_converter/conftest.py b/tests/input_converter/conftest.py index 337fe6d8..4f5179c4 100644 --- a/tests/input_converter/conftest.py +++ b/tests/input_converter/conftest.py @@ -245,17 +245,19 @@ def area_fr(local_study_with_hydro) -> Area: @pytest.fixture def fr_solar(area_fr) -> None: - return area_fr.create_solar(pd.DataFrame()) + return area_fr.create_solar(pd.DataFrame([1, 1, 1])) @pytest.fixture -def fr_wind(area_fr) -> None: - return area_fr.create_wind(pd.DataFrame()) +def fr_wind(area_fr, request) -> None: + command = request.param if hasattr(request, "param") else [1, 1, 1] + data = pd.DataFrame(command) + return area_fr.create_wind(data) @pytest.fixture def fr_load(area_fr) -> None: - return area_fr.create_load(pd.DataFrame()) + return area_fr.create_load(pd.DataFrame([1, 1, 1])) @pytest.fixture diff --git a/tests/input_converter/test_converter.py b/tests/input_converter/test_converter.py index 01086447..f5065374 100644 --- a/tests/input_converter/test_converter.py +++ b/tests/input_converter/test_converter.py @@ -19,6 +19,7 @@ InputStudy, parse_yaml_components, ) +import pytest class TestConverter: @@ -438,41 +439,6 @@ def test_convert_area_to_yaml(self, local_study_w_areas): validated_data.nodes.sort(key=lambda x: x.id) assert validated_data == expected_validated_data - def test_convert_wind_to_component(self, local_study_w_areas, fr_wind): - areas, converter = self._init_area_reading(local_study_w_areas) - - wind_components, wind_connection = converter._convert_wind_to_component_list( - areas - ) - study_path = converter.study_path - - wind_timeseries = str(study_path / "input" / "wind" / "series" / f"wind_fr.txt") - expected_wind_connection = [ - InputPortConnections( - component1="wind", - port_1="balance_port", - component2="fr", - port_2="balance_port", - ) - ] - expected_wind_components = InputComponent( - id="fr", - model="wind", - scenario_group=None, - parameters=[ - InputComponentParameter( - name="wind", - type="timeseries", - scenario_group=None, - value=None, - timeseries=f"{wind_timeseries}", - ), - ], - ) - - assert wind_components[0] == expected_wind_components - assert wind_connection == expected_wind_connection - def test_convert_solar_to_component(self, local_study_w_areas, fr_solar): areas, converter = self._init_area_reading(local_study_w_areas) @@ -544,3 +510,75 @@ def test_convert_load_to_component(self, local_study_w_areas, fr_load): assert load_components[0] == expected_load_components assert load_connection == expected_load_connection + + @pytest.mark.parametrize( + "fr_wind", + [ + [1, 1, 1], # Dataframe filled with 1 + ], + indirect=True, + ) + def test_convert_wind_to_component_not_empty_file( + self, local_study_w_areas, fr_wind + ): + areas, converter = self._init_area_reading(local_study_w_areas) + + wind_components, wind_connection = converter._convert_wind_to_component_list( + areas + ) + study_path = converter.study_path + + wind_timeseries = str(study_path / "input" / "wind" / "series" / f"wind_fr.txt") + expected_wind_connection = [ + InputPortConnections( + component1="wind", + port_1="balance_port", + component2="fr", + port_2="balance_port", + ) + ] + expected_wind_components = InputComponent( + id="fr", + model="wind", + scenario_group=None, + parameters=[ + InputComponentParameter( + name="wind", + type="timeseries", + scenario_group=None, + value=None, + timeseries=f"{wind_timeseries}", + ), + ], + ) + + assert wind_components[0] == expected_wind_components + assert wind_connection == expected_wind_connection + + @pytest.mark.parametrize( + "fr_wind", + [ + [], # DataFrame empty + ], + indirect=True, + ) + def test_convert_wind_to_component_empty_file(self, local_study_w_areas, fr_wind): + areas, converter = self._init_area_reading(local_study_w_areas) + + wind_components, _ = converter._convert_wind_to_component_list(areas) + + assert wind_components == [] + + @pytest.mark.parametrize( + "fr_wind", + [ + [0, 0, 0], # DataFrame full of 0 + ], + indirect=True, + ) + def test_convert_wind_to_component_zero_values(self, local_study_w_areas, fr_wind): + areas, converter = self._init_area_reading(local_study_w_areas) + + wind_components, _ = converter._convert_wind_to_component_list(areas) + + assert wind_components == [] From 974717082535ddb03676b263dfa0a5a2c9ab4643 Mon Sep 17 00:00:00 2001 From: killian-scalian Date: Mon, 13 Jan 2025 17:48:20 +0100 Subject: [PATCH 11/21] isort --- tests/input_converter/test_converter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/input_converter/test_converter.py b/tests/input_converter/test_converter.py index f5065374..8cf7669d 100644 --- a/tests/input_converter/test_converter.py +++ b/tests/input_converter/test_converter.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +import pytest from andromede.input_converter.src.converter import AntaresStudyConverter from andromede.input_converter.src.utils import transform_to_yaml @@ -19,7 +20,6 @@ InputStudy, parse_yaml_components, ) -import pytest class TestConverter: From b145e60a49cb759c5c8980fd1500c2099efa28c1 Mon Sep 17 00:00:00 2001 From: killian-scalian Date: Mon, 13 Jan 2025 17:51:34 +0100 Subject: [PATCH 12/21] mypy --- src/andromede/input_converter/src/converter.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/andromede/input_converter/src/converter.py b/src/andromede/input_converter/src/converter.py index 3dd2726c..cf1e8748 100644 --- a/src/andromede/input_converter/src/converter.py +++ b/src/andromede/input_converter/src/converter.py @@ -22,6 +22,7 @@ InputStudy, InputPortConnections, ) +from pandas import DataFrame class AntaresStudyConverter: @@ -38,7 +39,7 @@ def __init__(self, study_input: Union[Path, Study]): else: raise TypeError("Invalid input type") - def _validate_matrix(self, df): + def _validate_matrix(self, df: DataFrame)-> bool: """ Check and validate the following conditions: 1. The dataframe from this path is not empty. From 371ba8a089feaed91536e7182f05e6772009299e Mon Sep 17 00:00:00 2001 From: killian-scalian Date: Mon, 13 Jan 2025 17:53:03 +0100 Subject: [PATCH 13/21] lint --- src/andromede/input_converter/src/converter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/andromede/input_converter/src/converter.py b/src/andromede/input_converter/src/converter.py index cf1e8748..aac240e2 100644 --- a/src/andromede/input_converter/src/converter.py +++ b/src/andromede/input_converter/src/converter.py @@ -39,7 +39,7 @@ def __init__(self, study_input: Union[Path, Study]): else: raise TypeError("Invalid input type") - def _validate_matrix(self, df: DataFrame)-> bool: + def _validate_matrix(self, df: DataFrame) -> bool: """ Check and validate the following conditions: 1. The dataframe from this path is not empty. From 3497e77dfb477bbe051dd6a6828901adaf600fbe Mon Sep 17 00:00:00 2001 From: killian-scalian Date: Wed, 15 Jan 2025 11:06:07 +0100 Subject: [PATCH 14/21] modify validity method --- src/andromede/input_converter/src/converter.py | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/andromede/input_converter/src/converter.py b/src/andromede/input_converter/src/converter.py index aac240e2..4b0a7410 100644 --- a/src/andromede/input_converter/src/converter.py +++ b/src/andromede/input_converter/src/converter.py @@ -39,7 +39,7 @@ def __init__(self, study_input: Union[Path, Study]): else: raise TypeError("Invalid input type") - def _validate_matrix(self, df: DataFrame) -> bool: + def _check_dataframe_validity(self, df: DataFrame) -> bool: """ Check and validate the following conditions: 1. The dataframe from this path is not empty. @@ -47,10 +47,7 @@ def _validate_matrix(self, df: DataFrame) -> bool: :param df: dataframe to validate. """ - if df.empty: - return False - - if (df == 0).all().all(): + if df.empty or (df == 0).all().all(): return False return True @@ -199,7 +196,6 @@ def _convert_thermal_to_component_list( component2=area.id, port_2="balance_port", ) - ) return components, connections def _convert_wind_to_component_list( @@ -212,7 +208,6 @@ def _convert_wind_to_component_list( self.study_path / "input" / "wind" / "series" / f"wind_{area.id}.txt" ) if series_path.exists(): - if self._validate_matrix(area.get_wind_matrix()): components.append( InputComponent( id=area.id, @@ -248,7 +243,6 @@ def _convert_solar_to_component_list( ) if series_path.exists(): - if self._validate_matrix(area.get_solar_matrix()): components.extend( [ InputComponent( @@ -285,7 +279,6 @@ def _convert_load_to_component_list( self.study_path / "input" / "load" / "series" / f"load_{area.id}.txt" ) if series_path.exists(): - if self._validate_matrix(area.get_load_matrix()): components.extend( [ InputComponent( @@ -323,16 +316,13 @@ def convert_study_to_input_study(self) -> InputStudy: self._convert_wind_to_component_list, self._convert_solar_to_component_list, ] - list_components: list[InputComponent] = [] list_connections: list[InputPortConnections] = [] for method in conversion_methods: components, connections = method(areas) - if components: - list_components.extend(components) - if connections: - list_connections.extend(connections) + list_components.extend(components or []) + list_connections.extend(connections or []) return InputStudy( nodes=area_components, From bab9c89bc98ac82748a2e814e7d30a1c9751f9a6 Mon Sep 17 00:00:00 2001 From: killian-scalian Date: Wed, 15 Jan 2025 11:06:54 +0100 Subject: [PATCH 15/21] lre --- src/andromede/input_converter/src/converter.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/andromede/input_converter/src/converter.py b/src/andromede/input_converter/src/converter.py index 4b0a7410..8737a4d6 100644 --- a/src/andromede/input_converter/src/converter.py +++ b/src/andromede/input_converter/src/converter.py @@ -208,6 +208,7 @@ def _convert_wind_to_component_list( self.study_path / "input" / "wind" / "series" / f"wind_{area.id}.txt" ) if series_path.exists(): + if self._check_dataframe_validity(area.get_wind_matrix()): components.append( InputComponent( id=area.id, @@ -243,6 +244,7 @@ def _convert_solar_to_component_list( ) if series_path.exists(): + if self._check_dataframe_validity(area.get_solar_matrix()): components.extend( [ InputComponent( @@ -279,6 +281,7 @@ def _convert_load_to_component_list( self.study_path / "input" / "load" / "series" / f"load_{area.id}.txt" ) if series_path.exists(): + if self._check_dataframe_validity(area.get_load_matrix()): components.extend( [ InputComponent( From f92bd69601c92ee2dd532c0b2435c1f193f48aca Mon Sep 17 00:00:00 2001 From: killian-scalian Date: Wed, 15 Jan 2025 11:08:52 +0100 Subject: [PATCH 16/21] failure parsing --- src/andromede/input_converter/src/converter.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/andromede/input_converter/src/converter.py b/src/andromede/input_converter/src/converter.py index 8737a4d6..55b0d174 100644 --- a/src/andromede/input_converter/src/converter.py +++ b/src/andromede/input_converter/src/converter.py @@ -196,6 +196,7 @@ def _convert_thermal_to_component_list( component2=area.id, port_2="balance_port", ) + ) return components, connections def _convert_wind_to_component_list( @@ -312,6 +313,12 @@ def convert_study_to_input_study(self) -> InputStudy: areas = self.study.read_areas() area_components = self._convert_area_to_component_list(areas) + list_components: list[InputComponent] = [] + list_connections: list[InputPortConnections] = [] + + components, connections = self._convert_link_to_component_list() + list_components.extend(components) + list_connections.extend(connections) conversion_methods = [ self._convert_renewable_to_component_list, self._convert_thermal_to_component_list, @@ -319,8 +326,8 @@ def convert_study_to_input_study(self) -> InputStudy: self._convert_wind_to_component_list, self._convert_solar_to_component_list, ] - list_components: list[InputComponent] = [] - list_connections: list[InputPortConnections] = [] + + for method in conversion_methods: components, connections = method(areas) From 021a1f10d3fd5c25512a12feda7dc199968a0141 Mon Sep 17 00:00:00 2001 From: killian-scalian Date: Wed, 15 Jan 2025 11:25:03 +0100 Subject: [PATCH 17/21] formatting --- src/andromede/input_converter/src/converter.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/andromede/input_converter/src/converter.py b/src/andromede/input_converter/src/converter.py index 55b0d174..b5d4916d 100644 --- a/src/andromede/input_converter/src/converter.py +++ b/src/andromede/input_converter/src/converter.py @@ -316,9 +316,6 @@ def convert_study_to_input_study(self) -> InputStudy: list_components: list[InputComponent] = [] list_connections: list[InputPortConnections] = [] - components, connections = self._convert_link_to_component_list() - list_components.extend(components) - list_connections.extend(connections) conversion_methods = [ self._convert_renewable_to_component_list, self._convert_thermal_to_component_list, @@ -327,8 +324,6 @@ def convert_study_to_input_study(self) -> InputStudy: self._convert_solar_to_component_list, ] - - for method in conversion_methods: components, connections = method(areas) list_components.extend(components or []) From 0233101e5ef49c4873a3742408a8cd89f094deab Mon Sep 17 00:00:00 2001 From: killian-scalian Date: Wed, 15 Jan 2025 14:22:53 +0100 Subject: [PATCH 18/21] remove extend in some placesd --- src/andromede/input_converter/src/converter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/andromede/input_converter/src/converter.py b/src/andromede/input_converter/src/converter.py index b5d4916d..6ed83fa1 100644 --- a/src/andromede/input_converter/src/converter.py +++ b/src/andromede/input_converter/src/converter.py @@ -246,7 +246,7 @@ def _convert_solar_to_component_list( if series_path.exists(): if self._check_dataframe_validity(area.get_solar_matrix()): - components.extend( + components.append( [ InputComponent( id=area.id, @@ -283,7 +283,7 @@ def _convert_load_to_component_list( ) if series_path.exists(): if self._check_dataframe_validity(area.get_load_matrix()): - components.extend( + components.append( [ InputComponent( id=area.id, From dee638ad7471980bbc0c9bb20ff69a2154e76ebe Mon Sep 17 00:00:00 2001 From: killian-scalian Date: Wed, 15 Jan 2025 14:31:43 +0100 Subject: [PATCH 19/21] fix --- src/andromede/input_converter/src/converter.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/andromede/input_converter/src/converter.py b/src/andromede/input_converter/src/converter.py index 6ed83fa1..3cbc947d 100644 --- a/src/andromede/input_converter/src/converter.py +++ b/src/andromede/input_converter/src/converter.py @@ -247,7 +247,6 @@ def _convert_solar_to_component_list( if series_path.exists(): if self._check_dataframe_validity(area.get_solar_matrix()): components.append( - [ InputComponent( id=area.id, model="solar", @@ -259,7 +258,6 @@ def _convert_solar_to_component_list( ) ], ) - ] ) connections.append( InputPortConnections( @@ -284,7 +282,6 @@ def _convert_load_to_component_list( if series_path.exists(): if self._check_dataframe_validity(area.get_load_matrix()): components.append( - [ InputComponent( id=area.id, model="load", @@ -296,7 +293,7 @@ def _convert_load_to_component_list( ) ], ) - ] + ) connections.append( InputPortConnections( From 38dcba309a153e326c24059149f1cfb4ba5430fe Mon Sep 17 00:00:00 2001 From: killian-scalian Date: Wed, 15 Jan 2025 14:38:48 +0100 Subject: [PATCH 20/21] formatting --- .../input_converter/src/converter.py | 45 +++++++++---------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/src/andromede/input_converter/src/converter.py b/src/andromede/input_converter/src/converter.py index 3cbc947d..4f23f223 100644 --- a/src/andromede/input_converter/src/converter.py +++ b/src/andromede/input_converter/src/converter.py @@ -247,17 +247,17 @@ def _convert_solar_to_component_list( if series_path.exists(): if self._check_dataframe_validity(area.get_solar_matrix()): components.append( - InputComponent( - id=area.id, - model="solar", - parameters=[ - InputComponentParameter( - name="solar", - type="timeseries", - timeseries=str(series_path), - ) - ], - ) + InputComponent( + id=area.id, + model="solar", + parameters=[ + InputComponentParameter( + name="solar", + type="timeseries", + timeseries=str(series_path), + ) + ], + ) ) connections.append( InputPortConnections( @@ -282,18 +282,17 @@ def _convert_load_to_component_list( if series_path.exists(): if self._check_dataframe_validity(area.get_load_matrix()): components.append( - InputComponent( - id=area.id, - model="load", - parameters=[ - InputComponentParameter( - name="load", - type="timeseries", - timeseries=str(series_path), - ) - ], - ) - + InputComponent( + id=area.id, + model="load", + parameters=[ + InputComponentParameter( + name="load", + type="timeseries", + timeseries=str(series_path), + ) + ], + ) ) connections.append( InputPortConnections( From 36648008330986dc32bd8eda980a1e895e665d24 Mon Sep 17 00:00:00 2001 From: killian-scalian Date: Wed, 15 Jan 2025 15:01:13 +0100 Subject: [PATCH 21/21] one last fix --- src/andromede/input_converter/src/converter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/andromede/input_converter/src/converter.py b/src/andromede/input_converter/src/converter.py index 4f23f223..5f235a04 100644 --- a/src/andromede/input_converter/src/converter.py +++ b/src/andromede/input_converter/src/converter.py @@ -322,8 +322,8 @@ def convert_study_to_input_study(self) -> InputStudy: for method in conversion_methods: components, connections = method(areas) - list_components.extend(components or []) - list_connections.extend(connections or []) + list_components.extend(components) + list_connections.extend(connections) return InputStudy( nodes=area_components,