Skip to content

Commit

Permalink
Hydro heuristic problem as class
Browse files Browse the repository at this point in the history
  • Loading branch information
Juliette-Gerbaux committed Jun 28, 2024
1 parent ad1c6d1 commit 0d73822
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 159 deletions.
282 changes: 143 additions & 139 deletions src/andromede/hydro_heuristic/problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
#
# This file is part of the Antares project.

from typing import List

import ortools.linear_solver.pywraplp as pywraplp
import pandas as pd

Expand All @@ -22,7 +20,6 @@
TimeBlock,
build_problem,
)
from andromede.simulation.optimization import OptimizationProblem
from andromede.study import (
ConstantData,
DataBase,
Expand All @@ -36,139 +33,146 @@
from andromede.hydro_heuristic.data import HydroHeuristicData


def create_hydro_problem(
horizon: str,
hydro_data: HydroHeuristicData,
) -> OptimizationProblem:
database = generate_database(
hydro_data=hydro_data,
)

database = add_objective_coefficients_to_database(database, horizon)

time_block = TimeBlock(1, [i for i in range(len(hydro_data.target))])
scenarios = 1

hydro = create_component(
model=HeuristicHydroModelBuilder(HYDRO_MODEL, horizon).get_model(), id="H"
)

network = Network("test")
network.add_component(hydro)

problem = build_problem(
network,
database,
time_block,
scenarios,
border_management=(BlockBorderManagement.CYCLE),
)

return problem


def solve_hydro_problem(problem: OptimizationProblem) -> tuple[int, list[float], float]:
parameters = pywraplp.MPSolverParameters()
parameters.SetIntegerParam(parameters.PRESOLVE, parameters.PRESOLVE_OFF)
parameters.SetIntegerParam(parameters.SCALING, 0)
problem.solver.EnableOutput()

status = problem.solver.Solve(parameters)

output = OutputValues(problem)

return (
status,
output.component("H").var("generating").value[0], # type:ignore
output.component("H").var("level").value[0][-1], # type:ignore
)


def generate_database(
hydro_data: HydroHeuristicData,
) -> DataBase:
database = DataBase()

database.add_data("H", "capacity", ConstantData(hydro_data.capacity))
database.add_data("H", "initial_level", ConstantData(hydro_data.initial_level))

inflow_data = pd.DataFrame(
hydro_data.inflow,
index=[i for i in range(len(hydro_data.inflow))],
columns=[0],
)
database.add_data("H", "inflow", TimeScenarioSeriesData(inflow_data))

target_data = pd.DataFrame(
hydro_data.target,
index=[i for i in range(len(hydro_data.target))],
columns=[0],
)
database.add_data("H", "generating_target", TimeScenarioSeriesData(target_data))
database.add_data("H", "overall_target", ConstantData(sum(hydro_data.target)))

database.add_data(
"H",
"lower_rule_curve",
TimeSeriesData(
{
TimeIndex(i): hydro_data.lower_rule_curve[i] * hydro_data.capacity
for i in range(len(hydro_data.lower_rule_curve))
}
),
)
database.add_data(
"H",
"upper_rule_curve",
TimeSeriesData(
{
TimeIndex(i): hydro_data.upper_rule_curve[i] * hydro_data.capacity
for i in range(len(hydro_data.lower_rule_curve))
}
),
)
database.add_data("H", "min_generating", ConstantData(0))

database.add_data(
"H",
"max_generating",
TimeSeriesData(
{
TimeIndex(i): hydro_data.max_generating[i]
for i in range(len(hydro_data.max_generating))
}
),
)

database.add_data(
"H",
"max_epsilon",
TimeSeriesData(
{
TimeIndex(i): hydro_data.capacity if i == 0 else 0
for i in range(len(hydro_data.max_generating))
}
),
)

return database


def add_objective_coefficients_to_database(
database: DataBase, horizon: str
) -> DataBase:
objective_function_cost = {
"gamma_d": 1,
"gamma_delta": 1 if horizon == "monthly" else 2,
"gamma_y": 100000 if horizon == "monthly" else 68,
"gamma_w": 0 if horizon == "monthly" else 34,
"gamma_v+": 100 if horizon == "monthly" else 0,
"gamma_v-": 100 if horizon == "monthly" else 68,
"gamma_o": 0 if horizon == "monthly" else 23 * 68 + 1,
"gamma_s": 0 if horizon == "monthly" else -1 / 32,
}

for name, coeff in objective_function_cost.items():
database.add_data("H", name, ConstantData(coeff))

return database
class HydroHeuristicProblem:

def __init__(
self,
horizon: str,
hydro_data: HydroHeuristicData,
) -> None:

self.hydro_data = hydro_data
database = self.generate_database()

database = self.add_objective_coefficients_to_database(database, horizon)

time_block = TimeBlock(1, [i for i in range(len(hydro_data.target))])
scenarios = 1

hydro = create_component(
model=HeuristicHydroModelBuilder(HYDRO_MODEL, horizon).get_model(), id="H"
)

network = Network("test")
network.add_component(hydro)

problem = build_problem(
network,
database,
time_block,
scenarios,
border_management=(BlockBorderManagement.CYCLE),
)

self.problem = problem

def solve_hydro_problem(self) -> tuple[int, float, list[float], float]:
parameters = pywraplp.MPSolverParameters()
parameters.SetIntegerParam(parameters.PRESOLVE, parameters.PRESOLVE_OFF)
parameters.SetIntegerParam(parameters.SCALING, 0)
self.problem.solver.EnableOutput()

status = self.problem.solver.Solve(parameters)

output = OutputValues(self.problem)

return (
status,
self.problem.solver.Objective().Value(),
output.component("H").var("generating").value[0], # type:ignore
output.component("H").var("level").value[0][-1], # type:ignore
)

def generate_database(
self,
) -> DataBase:
database = DataBase()

database.add_data("H", "capacity", ConstantData(self.hydro_data.capacity))
database.add_data(
"H", "initial_level", ConstantData(self.hydro_data.initial_level)
)

inflow_data = pd.DataFrame(
self.hydro_data.inflow,
index=[i for i in range(len(self.hydro_data.inflow))],
columns=[0],
)
database.add_data("H", "inflow", TimeScenarioSeriesData(inflow_data))

target_data = pd.DataFrame(
self.hydro_data.target,
index=[i for i in range(len(self.hydro_data.target))],
columns=[0],
)
database.add_data("H", "generating_target", TimeScenarioSeriesData(target_data))
database.add_data(
"H", "overall_target", ConstantData(sum(self.hydro_data.target))
)

database.add_data(
"H",
"lower_rule_curve",
TimeSeriesData(
{
TimeIndex(i): self.hydro_data.lower_rule_curve[i]
* self.hydro_data.capacity
for i in range(len(self.hydro_data.lower_rule_curve))
}
),
)
database.add_data(
"H",
"upper_rule_curve",
TimeSeriesData(
{
TimeIndex(i): self.hydro_data.upper_rule_curve[i]
* self.hydro_data.capacity
for i in range(len(self.hydro_data.lower_rule_curve))
}
),
)
database.add_data("H", "min_generating", ConstantData(0))

database.add_data(
"H",
"max_generating",
TimeSeriesData(
{
TimeIndex(i): self.hydro_data.max_generating[i]
for i in range(len(self.hydro_data.max_generating))
}
),
)

database.add_data(
"H",
"max_epsilon",
TimeSeriesData(
{
TimeIndex(i): self.hydro_data.capacity if i == 0 else 0
for i in range(len(self.hydro_data.max_generating))
}
),
)

return database

def add_objective_coefficients_to_database(
self, database: DataBase, horizon: str
) -> DataBase:
objective_function_cost = {
"gamma_d": 1,
"gamma_delta": 1 if horizon == "monthly" else 2,
"gamma_y": 100000 if horizon == "monthly" else 68,
"gamma_w": 0 if horizon == "monthly" else 34,
"gamma_v+": 100 if horizon == "monthly" else 0,
"gamma_v-": 100 if horizon == "monthly" else 68,
"gamma_o": 0 if horizon == "monthly" else 23 * 68 + 1,
"gamma_s": 0 if horizon == "monthly" else -1 / 32,
}

for name, coeff in objective_function_cost.items():
database.add_data("H", name, ConstantData(coeff))

return database
23 changes: 10 additions & 13 deletions tests/functional/test_hydro_with_rulecurves.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@
# This file is part of the Antares project.

from typing import List

import ortools.linear_solver.pywraplp as pywraplp
import pytest

from andromede.hydro_heuristic.data import (
calculate_weekly_target,
get_number_of_days_in_month,
HydroHeuristicData,
)
from andromede.hydro_heuristic.problem import create_hydro_problem, solve_hydro_problem
from andromede.hydro_heuristic.problem import HydroHeuristicProblem


def test_hydro_heuristic() -> None:
Expand All @@ -42,15 +42,13 @@ def test_hydro_heuristic() -> None:
monthly_data.compute_target(sum(monthly_data.inflow))

# Ajustement de la réapartition mensuelle
problem = create_hydro_problem(horizon="monthly", hydro_data=monthly_data)
problem = HydroHeuristicProblem(horizon="monthly", hydro_data=monthly_data)

status, monthly_generation, _ = solve_hydro_problem(problem)
status, obj, monthly_generation, _ = problem.solve_hydro_problem()

assert status == problem.solver.OPTIMAL
assert status == pywraplp.Solver.OPTIMAL

assert problem.solver.Objective().Value() / capacity == pytest.approx(
10.1423117689793
)
assert obj / capacity == pytest.approx(10.1423117689793)

monthly_generation = [
capacity * target
Expand Down Expand Up @@ -89,12 +87,11 @@ def test_hydro_heuristic() -> None:
total_target=monthly_generation[month],
)
# Ajustement de la répartition jour par jour
problem = create_hydro_problem(horizon="daily", hydro_data=daily_data)

status, daily_generation, initial_level = solve_hydro_problem(problem)
problem = HydroHeuristicProblem(horizon="daily", hydro_data=daily_data)

assert status == problem.solver.OPTIMAL
assert problem.solver.Objective().Value() / capacity == pytest.approx(
status, obj, daily_generation, initial_level = problem.solve_hydro_problem()
assert status == pywraplp.Solver.OPTIMAL
assert obj / capacity == pytest.approx(
[
-0.405595,
-0.354666,
Expand Down
Loading

0 comments on commit 0d73822

Please sign in to comment.