Skip to content

End to end test refactorization for input converter #95

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions src/andromede/input_converter/src/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,16 +296,17 @@ def _convert_st_storage_to_component_list(
value=storage.properties.efficiency,
),
# TODO wait for update of antares craft that support the 9.2 version of Antares
# InputComponentParameter(
# id="efficiency_withdrawal",
# time_dependent=False,
# scenario_dependent=False,
# value=storage.properties.efficiencywithdrawal,
# ),
InputComponentParameter(
id="efficiency_withdrawal",
time_dependent=False,
scenario_dependent=False,
value=1,
# value=storage.properties.efficiencywithdrawal,
),
InputComponentParameter(
id="initial_level",
time_dependent=False,
scenario_dependent=True,
scenario_dependent=False,
value=storage.properties.initial_level,
),
InputComponentParameter(
Expand Down
2 changes: 1 addition & 1 deletion src/andromede/libs/antares_historic/antares_historic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ library:
scenario-dependent: true
- id: initial_level
time-dependent: false
scenario-dependent: true
scenario-dependent: false
variables:
- id: p_injection
lower-bound: 0
Expand Down
31 changes: 31 additions & 0 deletions tests/antares_historic/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
# This file is part of the Antares project.
import pytest
from antares.craft.model.area import AreaProperties
from antares.craft.model.st_storage import STStorageProperties
from antares.craft.model.study import Study, create_study_local
from antares.craft.model.thermal import (
LawOption,
Expand Down Expand Up @@ -105,3 +106,33 @@ def local_study_end_to_end_w_thermal(local_study, default_thermal_cluster_proper
thermal_name, properties=default_thermal_cluster_properties
)
return local_study


@pytest.fixture
def default_st_storage_cluster_properties() -> STStorageProperties:
return STStorageProperties(
injection_nominal_capacity=10,
withdrawal_nominal_capacity=10,
reservoir_capacity=150,
efficiency=1,
initial_level=0.5,
initial_level_optim=False,
enabled=True,
)


@pytest.fixture
def local_study_with_st_storage(
local_study_end_to_end_w_thermal, default_st_storage_cluster_properties
) -> Study:
"""
Create an empty study
Create an area with custom area properties
Create a thermal cluster with custom thermal properties
Create a short term storage
"""
storage_name = "battery"
local_study_end_to_end_w_thermal.get_areas()["fr"].create_st_storage(
storage_name, properties=default_st_storage_cluster_properties
)
return local_study_end_to_end_w_thermal
102 changes: 56 additions & 46 deletions tests/antares_historic/test_antares_historic.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from dataclasses import dataclass
from pathlib import Path

import pandas as pd
Expand All @@ -8,6 +9,7 @@
from andromede.model.parsing import InputLibrary, parse_yaml_library
from andromede.model.resolve_library import resolve_library
from andromede.simulation import TimeBlock, build_problem
from andromede.simulation.optimization import OptimizationProblem
from andromede.study.data import load_ts_from_txt
from andromede.study.parsing import InputSystem, parse_yaml_components
from andromede.study.resolve_components import (
Expand All @@ -18,7 +20,13 @@
)


def create_csv_from_constant_value(
@dataclass(frozen=True)
class ToolTestStudy:
study_component_data: InputSystem
study_path: Path


def write_csv_with_constant_value(
path, filename: str, lines: int, columns: int = 1, value: float = 1
) -> None:
"""
Expand All @@ -31,38 +39,22 @@ def create_csv_from_constant_value(
columns (int): Number of columns in the file.
value (float): Value to fill in the columns.

Returns:
Path: Path to the created file.
"""
# Create the directory if it does not exist
Path(path).mkdir(parents=True, exist_ok=True)
path = path / filename

# Generate the data
data = {f"col_{i+1}": [value] * lines for i in range(columns)}
df = pd.DataFrame(data)

# Write the data to a file
df.to_csv(
path.with_suffix(".txt"),
sep="\t",
index=False,
header=False,
encoding="utf-8",
)
write_csv_with_df(path, filename, df)


def write_df_to_csv(path, filename: str, df: pd.DataFrame) -> None:
def write_csv_with_df(path, filename: str, df: pd.DataFrame) -> None:
"""
Creates a file from an existing DataFrame.

Args:
path (Path): Path to the directory where the file will be created.
filename (str): Name of the file to be created.
df (pd.DataFrame): DataFrame containing the data to be written.

Returns:
Path: Path to the created file.
"""
# Create the directory if it does not exist
Path(path).mkdir(parents=True, exist_ok=True)
Expand All @@ -86,7 +78,7 @@ def data_dir() -> Path:
Returns:
Path: Path to the data directory.
"""
return Path(__file__).parent.parent.parent
return Path(__file__).parents[2]


def fill_timeseries(study_path) -> None:
Expand All @@ -112,19 +104,19 @@ def fill_timeseries(study_path) -> None:
)

# Create the files with the data
write_df_to_csv(path=load_timeseries, filename="load_fr", df=demand_data)
create_csv_from_constant_value(
write_csv_with_df(path=load_timeseries, filename="load_fr", df=demand_data)
write_csv_with_constant_value(
path=prepro_path, filename="modulation", lines=3, columns=4, value=0
)
create_csv_from_constant_value(
write_csv_with_constant_value(
path=series_path, filename="series", lines=3, columns=1, value=151
)
create_csv_from_constant_value(path=series_path, filename="p_min_cluster", lines=3)
create_csv_from_constant_value(path=series_path, filename="nb_units_min", lines=3)
create_csv_from_constant_value(path=series_path, filename="nb_units_max", lines=3)
write_csv_with_constant_value(path=series_path, filename="p_min_cluster", lines=3)
write_csv_with_constant_value(path=series_path, filename="nb_units_min", lines=3)
write_csv_with_constant_value(path=series_path, filename="nb_units_max", lines=3)


def _setup_study_component(study, period=None) -> tuple:
def _setup_study_component(study, period=None) -> ToolTestStudy:
"""
Helper function to reduce redundancy in study component setup.
"""
Expand All @@ -142,19 +134,24 @@ def _setup_study_component(study, period=None) -> tuple:

compo_file = converter.output_path
with compo_file.open() as c:
return parse_yaml_components(c), study_path
return ToolTestStudy(parse_yaml_components(c), study_path)


@pytest.fixture
def study_component_basic(local_study_end_to_end_simple) -> tuple:
def study_component_basic(local_study_end_to_end_simple) -> ToolTestStudy:
return _setup_study_component(local_study_end_to_end_simple)


@pytest.fixture
def study_component_thermal(local_study_end_to_end_w_thermal) -> tuple:
def study_component_thermal(local_study_end_to_end_w_thermal) -> ToolTestStudy:
return _setup_study_component(local_study_end_to_end_w_thermal, period=3)


@pytest.fixture
def study_component_st_storage(local_study_with_st_storage) -> ToolTestStudy:
return _setup_study_component(local_study_with_st_storage, period=3)


@pytest.fixture
def input_library(
data_dir: Path,
Expand All @@ -171,33 +168,29 @@ def input_library(
return parse_yaml_library(lib)


def factory_balance_using_converter(
input_system: InputSystem, input_library: InputLibrary, expected_value: int
) -> None:
def build_test_problem(
study_test_component: ToolTestStudy, input_library: InputLibrary
) -> OptimizationProblem:
"""
- Resolves the input library.
- Constructs components and connections.
- Performs consistency checks.
- Builds the database and network.
- Solves the optimization problem and verifies results.
"""
study_path = input_system[1]
study_component_data = input_system[0]
study_path = study_test_component.study_path
study_component_data = study_test_component.study_component_data

result_lib = resolve_library([input_library])
components_input = resolve_system(study_component_data, result_lib)
consistency_check(
components_input.components, result_lib["antares-historic"].models
)

database = build_data_base(study_component_data, study_path)
network = build_network(components_input)

scenarios = 1
problem = build_problem(network, database, TimeBlock(1, [0, 1]), scenarios)
status = problem.solver.Solve()
assert status == problem.solver.OPTIMAL
assert problem.solver.Objective().Value() == expected_value
return build_problem(network, database, TimeBlock(1, [0, 1]), scenarios)


def test_basic_balance_using_converter(
Expand All @@ -206,9 +199,10 @@ def test_basic_balance_using_converter(
"""
Test basic study balance using the converter.
"""
factory_balance_using_converter(
study_component_basic, input_library, expected_value=150
)
problem = build_test_problem(study_component_basic, input_library)
status = problem.solver.Solve()
assert status == problem.solver.OPTIMAL
assert problem.solver.Objective().Value() == 150


def test_thermal_balance_using_converter(
Expand All @@ -217,6 +211,22 @@ def test_thermal_balance_using_converter(
"""
Test thermal study balance using the converter.
"""
factory_balance_using_converter(
study_component_thermal, input_library, expected_value=165
)
problem = build_test_problem(study_component_thermal, input_library)

status = problem.solver.Solve()
assert status == problem.solver.OPTIMAL
assert problem.solver.Objective().Value() == 165


# @pytest.mark.skip("Pass test for the moment")
def test_storage_balance_using_converter(
study_component_st_storage: InputSystem, input_library: InputLibrary
) -> None:
"""
Test storage study balance using the converter.
"""
problem = build_test_problem(study_component_st_storage, input_library)

status = problem.solver.Solve()
assert status == problem.solver.OPTIMAL
assert int(problem.solver.Objective().Value()) == 165
9 changes: 8 additions & 1 deletion tests/input_converter/test_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,10 +317,17 @@ def test_convert_st_storages_to_component(
scenario_group=None,
value=1,
),
InputComponentParameter(
id="efficiency_withdrawal",
time_dependent=False,
scenario_dependent=False,
scenario_group=None,
value=1,
),
InputComponentParameter(
id="initial_level",
time_dependent=False,
scenario_dependent=True,
scenario_dependent=False,
scenario_group=None,
value=0.5,
),
Expand Down
Loading