Skip to content

Commit

Permalink
See #18 Refactor tests to separate functional, ut and integration
Browse files Browse the repository at this point in the history
  • Loading branch information
ianmnz committed Feb 28, 2024
1 parent 9fc4464 commit 45ed520
Show file tree
Hide file tree
Showing 19 changed files with 234 additions and 51 deletions.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
PortRef,
create_component,
)
from tests.andromede.test_utils import generate_data
from tests.unittests.test_utils import generate_data


def test_large_sum_with_loop() -> None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
PortRef,
create_component,
)
from tests.andromede.test_utils import generate_data
from tests.unittests.test_utils import generate_data


@pytest.fixture
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,55 +316,6 @@ def test_two_candidates_xpansion_single_time_step_single_scenario(
assert output == expected_output, f"Output differs from expected: {output}"


def test_model_export_xpansion_single_time_step_single_scenario(
generator: Component,
candidate: Component,
cluster_candidate: Component,
) -> None:
"""
Same test as before but this time we separate master/subproblem and
export the problems in MPS format to be solved by the Benders solver in Xpansion
"""

database = DataBase()
database.add_data("D", "demand", ConstantData(400))

database.add_data("N", "spillage_cost", ConstantData(1))
database.add_data("N", "ens_cost", ConstantData(501))

database.add_data("G1", "p_max", ConstantData(200))
database.add_data("G1", "cost", ConstantData(45))

database.add_data("CAND", "op_cost", ConstantData(10))
database.add_data("CAND", "invest_cost", ConstantData(490))

database.add_data("DISCRETE", "op_cost", ConstantData(10))
database.add_data("DISCRETE", "invest_cost", ConstantData(200))
database.add_data("DISCRETE", "p_max_per_unit", ConstantData(10))

demand = create_component(model=DEMAND_MODEL, id="D")

node = Node(model=NODE_WITH_SPILL_AND_ENS_MODEL, id="N")
network = Network("test")
network.add_node(node)
network.add_component(demand)
network.add_component(generator)
network.add_component(candidate)
network.add_component(cluster_candidate)
network.connect(PortRef(demand, "balance_port"), PortRef(node, "balance_port"))
network.connect(PortRef(generator, "balance_port"), PortRef(node, "balance_port"))
network.connect(PortRef(candidate, "balance_port"), PortRef(node, "balance_port"))
network.connect(
PortRef(cluster_candidate, "balance_port"), PortRef(node, "balance_port")
)
scenarios = 1

xpansion = build_benders_decomposed_problem(
network, database, TimeBlock(1, [0]), scenarios
)
assert xpansion.run()


def test_generation_xpansion_two_time_steps_two_scenarios(
generator: Component,
candidate: Component,
Expand Down
File renamed without changes.
210 changes: 210 additions & 0 deletions tests/integration/test_benders_decomposed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
# Copyright (c) 2024, RTE (https://www.rte-france.com)
#
# See AUTHORS.txt
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# SPDX-License-Identifier: MPL-2.0
#
# This file is part of the Antares project.

import pytest

from andromede.expression.expression import literal, param, var
from andromede.expression.indexing_structure import IndexingStructure
from andromede.libs.standard import (
BALANCE_PORT_TYPE,
CONSTANT,
DEMAND_MODEL,
GENERATOR_MODEL,
NODE_BALANCE_MODEL,
NODE_WITH_SPILL_AND_ENS_MODEL,
)
from andromede.model import (
Constraint,
Model,
ModelPort,
ProblemContext,
float_parameter,
float_variable,
int_variable,
model,
)
from andromede.model.model import PortFieldDefinition, PortFieldId
from andromede.simulation import TimeBlock, build_benders_decomposed_problem
from andromede.study import (
Component,
ConstantData,
DataBase,
Network,
Node,
PortRef,
create_component,
)

CONSTANT = IndexingStructure(False, False)
FREE = IndexingStructure(True, True)

INVESTMENT = ProblemContext.INVESTMENT
OPERATIONAL = ProblemContext.OPERATIONAL
COUPLING = ProblemContext.COUPLING


@pytest.fixture
def thermal_candidate() -> Model:
THERMAL_CANDIDATE = model(
id="GEN",
parameters=[
float_parameter("op_cost", CONSTANT),
float_parameter("invest_cost", CONSTANT),
],
variables=[
float_variable("generation", lower_bound=literal(0)),
float_variable(
"p_max",
lower_bound=literal(0),
upper_bound=literal(1000),
structure=CONSTANT,
context=COUPLING,
),
],
ports=[ModelPort(port_type=BALANCE_PORT_TYPE, port_name="balance_port")],
port_fields_definitions=[
PortFieldDefinition(
port_field=PortFieldId("balance_port", "flow"),
definition=var("generation"),
)
],
constraints=[
Constraint(
name="Max generation", expression=var("generation") <= var("p_max")
)
],
objective_operational_contribution=(param("op_cost") * var("generation"))
.sum()
.expec(),
objective_investment_contribution=param("invest_cost") * var("p_max"),
)
return THERMAL_CANDIDATE


@pytest.fixture
def discrete_candidate() -> Model:
DISCRETE_CANDIDATE = model(
id="DISCRETE",
parameters=[
float_parameter("op_cost", CONSTANT),
float_parameter("invest_cost", CONSTANT),
float_parameter("p_max_per_unit", CONSTANT),
],
variables=[
float_variable("generation", lower_bound=literal(0)),
float_variable(
"p_max",
lower_bound=literal(0),
structure=CONSTANT,
context=COUPLING,
),
int_variable(
"nb_units",
lower_bound=literal(0),
upper_bound=literal(10),
structure=CONSTANT,
context=INVESTMENT,
),
],
ports=[ModelPort(port_type=BALANCE_PORT_TYPE, port_name="balance_port")],
port_fields_definitions=[
PortFieldDefinition(
port_field=PortFieldId("balance_port", "flow"),
definition=var("generation"),
)
],
constraints=[
Constraint(
name="Max generation", expression=var("generation") <= var("p_max")
),
Constraint(
name="Max investment",
expression=var("p_max") == param("p_max_per_unit") * var("nb_units"),
context=INVESTMENT,
),
],
objective_operational_contribution=(param("op_cost") * var("generation"))
.sum()
.expec(),
objective_investment_contribution=param("invest_cost") * var("p_max"),
)
return DISCRETE_CANDIDATE


@pytest.fixture
def generator() -> Component:
generator = create_component(
model=GENERATOR_MODEL,
id="G1",
)
return generator


@pytest.fixture
def candidate(thermal_candidate: Model) -> Component:
candidate = create_component(model=thermal_candidate, id="CAND")
return candidate


@pytest.fixture
def cluster_candidate(discrete_candidate: Model) -> Component:
cluster = create_component(model=discrete_candidate, id="DISCRETE")
return cluster


def test_benders_decomposed_single_time_step_single_scenario(
generator: Component,
candidate: Component,
cluster_candidate: Component,
) -> None:
"""
Same test as before but this time we separate master/subproblem and
export the problems in MPS format to be solved by the Benders solver in Xpansion
"""

database = DataBase()
database.add_data("D", "demand", ConstantData(400))

database.add_data("N", "spillage_cost", ConstantData(1))
database.add_data("N", "ens_cost", ConstantData(501))

database.add_data("G1", "p_max", ConstantData(200))
database.add_data("G1", "cost", ConstantData(45))

database.add_data("CAND", "op_cost", ConstantData(10))
database.add_data("CAND", "invest_cost", ConstantData(490))

database.add_data("DISCRETE", "op_cost", ConstantData(10))
database.add_data("DISCRETE", "invest_cost", ConstantData(200))
database.add_data("DISCRETE", "p_max_per_unit", ConstantData(10))

demand = create_component(model=DEMAND_MODEL, id="D")

node = Node(model=NODE_WITH_SPILL_AND_ENS_MODEL, id="N")
network = Network("test")
network.add_node(node)
network.add_component(demand)
network.add_component(generator)
network.add_component(candidate)
network.add_component(cluster_candidate)
network.connect(PortRef(demand, "balance_port"), PortRef(node, "balance_port"))
network.connect(PortRef(generator, "balance_port"), PortRef(node, "balance_port"))
network.connect(PortRef(candidate, "balance_port"), PortRef(node, "balance_port"))
network.connect(
PortRef(cluster_candidate, "balance_port"), PortRef(node, "balance_port")
)
scenarios = 1

xpansion = build_benders_decomposed_problem(
network, database, TimeBlock(1, [0]), scenarios
)
assert xpansion.run()
11 changes: 11 additions & 0 deletions tests/unittests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Copyright (c) 2024, RTE (https://www.rte-france.com)
#
# See AUTHORS.txt
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# SPDX-License-Identifier: MPL-2.0
#
# This file is part of the Antares project.
11 changes: 11 additions & 0 deletions tests/unittests/expressions/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Copyright (c) 2024, RTE (https://www.rte-france.com)
#
# See AUTHORS.txt
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# SPDX-License-Identifier: MPL-2.0
#
# This file is part of the Antares project.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 comments on commit 45ed520

Please sign in to comment.