Skip to content
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

Hydro heuristic #41

Open
wants to merge 54 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
947b637
Hydro heuristic on a complex test case
Jun 19, 2024
ac42ad6
Another test on hydro heuristic
Jun 21, 2024
3dddf92
Api for hydrp heuristic model
Jun 21, 2024
1b4da8d
Sort imports
Jun 24, 2024
47ad90e
Run isort
Jun 24, 2024
fad5974
Formatting
Jun 24, 2024
49f06ed
Change hydro model to model
Jun 24, 2024
b9852d8
Remove costs from model
Jun 24, 2024
9d5a7a4
Factorize code
Jun 24, 2024
49bdf53
Unique function to aggregate data
Jun 24, 2024
8306753
Move models to lib
Jun 27, 2024
0434b5c
Mode functions in tests to src
Jun 27, 2024
873a837
Fix ci
Jun 28, 2024
1be0f20
Rename tests
Jun 28, 2024
e6af454
Class for heuristic model building
Jun 28, 2024
ad1c6d1
Class for hydro data
Jun 28, 2024
0d73822
Hydro heuristic problem as class
Jun 28, 2024
3d55426
Fix ci
Jun 28, 2024
2156480
Unique function to compute monthly and daily targets
Jul 1, 2024
2374fb1
More tests
Jul 1, 2024
2bd37c3
Fix test
Jul 1, 2024
614f554
Decompose yearly problem into weekly problems for hydro
Jul 2, 2024
b44ce6c
Absolute path for data
Jul 8, 2024
ba638cf
New test without inflow
Jul 9, 2024
7ad0947
New test
Jul 9, 2024
363c92e
Complete test with rule curves
Jul 12, 2024
a81560c
Take into account rule curves in complete year
Jul 12, 2024
ee70403
New test
Jul 12, 2024
30bb910
Fix tests
Jul 12, 2024
9d188f8
Fix ci
Jul 12, 2024
5a95f03
Fix ci
Jul 12, 2024
a6a5037
Refactor and add tests
Jul 31, 2024
7f7ae05
Exhibit models
Aug 1, 2024
c822259
Refactor compute target
Aug 5, 2024
536603e
Fix tests
Aug 5, 2024
78c78ac
Fix tests
Aug 5, 2024
fad672e
Remove unused imports
Aug 5, 2024
38ea51c
New test on small reservoir
Aug 6, 2024
5834e6d
Complete test
Aug 6, 2024
f447eb1
Fix ci
Aug 6, 2024
9edd374
Add test with infeasibilities
Aug 9, 2024
1b6cccb
Add description for tests
Aug 9, 2024
c489b9a
Change list type hint
Aug 20, 2024
06ff7be
Improve data.py
Aug 20, 2024
b53a7d7
Better errors in heuristic model
Aug 20, 2024
5d60710
Type hint error
Aug 20, 2024
232e78b
Small corrections
Aug 20, 2024
800bc90
Improve test
Aug 20, 2024
6650303
Move data
Aug 20, 2024
04bdbbb
Improve data
Aug 21, 2024
9dccf80
More explicit names
Aug 21, 2024
4f47103
Better workflow
Aug 23, 2024
b21f1f0
Fix tests
Aug 23, 2024
d74fff3
Fix ci
Aug 23, 2024
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
Prev Previous commit
Next Next commit
New test
Juliette-Gerbaux committed Jul 12, 2024
commit ee70403a87f848314e4cd9d2495f366b36117740
2 changes: 1 addition & 1 deletion src/andromede/libs/standard.py
Original file line number Diff line number Diff line change
@@ -112,7 +112,7 @@
GENERATOR_MODEL = model(
id="GEN",
parameters=[
float_parameter("p_max", CONSTANT),
float_parameter("p_max", TIME_AND_SCENARIO_FREE),
float_parameter("cost", CONSTANT),
],
variables=[float_variable("generation", lower_bound=literal(0))],
59 changes: 59 additions & 0 deletions tests/functional/data/hydro_with_unavailibility/values-weekly.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
Area area va weekly
VARIABLES BEGIN END
13 1 52

Area weekly OV. COST OP. COST LOAD NUCLEAR COAL GAS H. STOR H. PUMP H. LEV H. INFL H. OVFL UNSP. ENRG SPIL. ENRG
Euro Euro MWh MWh MWh MWh MWh MWh % MWh % MWh MWh
week
1 1235289670 1235289670 8286984 5040000 1037632 2100000 387094 277742 43.61 32011 0 0 0
2 1288555793 1288555793 8466912 5040000 1215186 2100000 519129 407403 42.69 31766 0 0 0
3 1287342023 1287342023 8462812 5040000 1211140 2100000 419539 307867 41.78 31563 0 0 0
4 1551419900 1302000000 8596577 5040000 1260000 2100000 469565 356128 40.91 31556 0 83140 0
5 1287341441 1287341441 8413755 5040000 1211138 2100000 414490 351873 40.16 31619 0 0 0
6 1521863068 1302000000 8497279 5040000 1260000 2100000 363275 339284 40.37 31703 0 73288 0
7 1749207341 1302000000 8573275 5040000 1260000 2100000 362845 338639 40.35 32270 0 149069 0
8 1362938031 1302000000 8444154 5040000 1260000 2100000 400682 376841 40.51 33698 0 20313 0
9 1728657188 1302000000 8603481 5040000 1260000 2100000 366713 305451 40.50 35693 0 142219 0
10 1574949518 1302000000 8580828 5040000 1260000 2100000 354719 264874 40.52 37779 0 90983 0
11 1277412929 1277412929 8406058 5040000 1178043 2100000 399040 311025 39.46 40600 0 0 0
12 1283611639 1283611639 8426939 5040000 1198705 2100000 411532 323298 39.40 44723 0 0 0
13 1248049296 1248049296 8295678 5040000 1080164 2100000 371364 295850 38.85 49721 0 0 0
14 1233892800 1233892800 8172976 5040000 1032976 2100000 348444 348444 38.54 54803 0 0 0
15 1164750900 1164750900 7942503 5040000 802503 2100000 237395 237395 39.52 60606 0 0 0
16 1143859200 1143859200 7872864 5040000 732864 2100000 201877 201877 40.42 69083 0 0 0
17 1167444900 1167444900 7951483 5040000 811483 2100000 220189 220189 41.17 80234 0 0 0
18 1104053100 1104053100 7740177 5040000 600177 2100000 157566 157566 42.11 92113 0 0 0
19 1100553000 1100553000 7728510 5040000 588510 2100000 152346 152346 42.97 104713 0 0 0
20 1065877800 1065877800 7612926 5040000 472926 2100000 216070 216070 43.90 122668 0 0 0
21 1040929500 1040929500 7529765 5040000 389765 2100000 276855 276855 45.51 147504 0 0 0
22 1020957000 1020957000 7463190 5040000 323190 2100000 289108 289108 46.97 175497 0 0 0
23 1034965500 1034965500 7509885 5040000 369885 2100000 259385 259385 48.60 203441 0 0 0
24 1013723100 1013723100 7439077 5040000 299077 2100000 325736 325736 50.56 226058 0 0 0
25 908301000 908301000 7061505 5040000 0 2021505 366567 366567 53.03 237083 0 0 0
26 913409200 913409200 7087046 5040000 0 2047046 378549 378549 55.43 239099 0 0 0
27 907086000 907086000 7055430 5040000 0 2015430 408575 408575 57.71 239897 0 0 0
28 850235000 850235000 6771175 5040000 0 1731175 290302 290302 60.66 238945 0 0 0
29 893271600 893271600 6986358 5040000 0 1946358 392247 392247 62.96 231602 0 0 0
30 836477800 836477800 6702389 5040000 0 1662389 235471 235471 65.01 217847 0 0 0
31 851249600 851249600 6776248 5040000 0 1736248 282062 282062 67.11 202356 0 0 0
32 857109731 857109731 6858384 5040000 0 1765549 314326 261491 68.85 186900 0 0 0
33 872228247 872228247 6945312 5040000 0 1841141 269636 205465 70.42 171906 0 0 0
34 878973093 878973093 6984753 5040000 0 1874865 389397 319509 70.80 157584 0 0 0
35 865552929 865552929 6965455 5040000 0 1807765 322728 205038 71.80 143654 0 0 0
36 907137360 907137360 6982725 4550000 107125 2100000 487501 261901 72.51 129745 0 0 0
37 1222337724 1134000000 6974790 3360000 1260000 2100000 528592 303248 70.07 116739 0 29446 0
38 1227072601 1134000000 6976421 3360000 1260000 2100000 551477 326080 69.10 106232 0 31024 0
39 1639619634 1134000000 7157827 3360000 1260000 2100000 479551 210264 67.37 97944 0 168540 0
40 1878745802 1134000000 7188997 3360000 1260000 2100000 422311 201563 66.22 90090 0 248249 0
41 1982920638 1134000000 7224822 3360000 1260000 2100000 404407 182559 65.21 82551 0 282974 0
42 1114673845 1114673845 7251583 3920000 1008913 2100000 621756 399086 61.79 76629 0 0 0
43 977131827 977131827 7548906 5040000 177106 2100000 482499 250699 61.74 72534 0 0 0
44 1022669353 1022669353 7704588 5040000 328898 2100000 421566 185876 60.03 69104 0 0 0
45 956957112 956957112 7477915 5040000 109857 2100000 464451 236393 58.45 65632 0 0 0
46 1006470669 1006470669 7648152 5040000 274902 2100000 436497 203247 57.20 61362 0 0 0
47 1056025237 1056025237 7818530 5040000 440084 2100000 401838 163392 55.28 55664 0 0 0
48 1121050883 1121050883 8038910 5040000 656836 2100000 328479 86405 53.54 49014 0 0 0
49 1093556009 1093556009 7936024 5040000 565187 2100000 391546 160709 51.20 42294 0 0 0
50 1189838317 1189838317 8266580 5040000 886128 2100000 445000 204548 49.54 36547 0 0 0
51 1182896679 1182896679 8242748 5040000 862989 2100000 398352 158593 47.63 33495 0 0 0
52 1183885845 1183885845 8246144 5040000 866286 2100000 344271 104413 45.38 32844 0 0 0
435 changes: 435 additions & 0 deletions tests/functional/test_hydro_with_unavaibility.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,435 @@
# 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.

from typing import List

import numpy as np
import ortools.linear_solver.pywraplp as pywraplp
import pytest

from andromede.hydro_heuristic.data import (
calculate_weekly_target,
get_number_of_days_in_month,
update_generation_target,
)
from andromede.hydro_heuristic.problem import optimize_target
from andromede.libs.standard import (
DEMAND_MODEL,
GENERATOR_MODEL,
NODE_WITH_SPILL_AND_ENS_MODEL,
)
from andromede.model.model import Model
from andromede.simulation import OutputValues, TimeBlock, build_problem
from andromede.study import (
ConstantData,
DataBase,
Network,
Node,
PortRef,
TimeIndex,
TimeSeriesData,
create_component,
)
from tests.functional.libs.lib_hydro_heuristic import (
HYDRO_MODEL_RULE_CURVES,
HYDRO_MODEL_WITH_TARGET,
)

from pathlib import Path

optimal_generation = np.array(
[
970769.54166667,
861569.45833333,
62812.0,
200749.91666667,
141134.41666667,
126312.5,
363693.41666667,
108870.0,
282407.75,
195624.33333333,
224115.45833333,
178595.75,
169385.41666667,
218124.83333333,
-23170.375,
-95656.125,
-14351.70833333,
-126658.0,
-505373.25,
-500585.33333333,
-506195.75,
-502971.33333333,
-233037.0,
-241259.75,
-188374.75,
-179215.0,
-196510.5,
-368825.0,
-153642.0,
-437611.0,
-363752.0,
-281616.0,
-194688.0,
-155247.0,
-174545.0,
322725.0,
1514790.0,
864940.58333337,
437827.0,
468997.0,
504822.0,
387070.875,
337153.625,
242701.0,
125085.33333333,
305316.91666667,
187429.08333333,
171796.66666667,
-334815.0,
-133420.0,
552651.0,
670764.0,
]
)

expected_monthly_generation = [
143339.17635433562,
448143.8236456645,
392228.0,
0.0,
0.0,
0.0,
0.0,
283540.0,
880464.8715492995,
972585.5404387095,
987207.2977588804,
1183898.2902531116,
]

expected_weekly_target = [
30219.22973453103,
32189.06192005993,
32090.851046477324,
33776.2766893666,
72029.72533763104,
112192.22152202608,
115734.09776498083,
110161.39372895012,
103880.17373520866,
92151.52451197282,
87515.61080253527,
87384.7023261077,
74386.13088015263,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
51468.71296816808,
63986.14580114127,
65689.2387701995,
123439.9024604901,
207457.9600766448,
203081.78857398863,
204202.69822189954,
244678.42467676676,
202285.23332789773,
205663.19866574876,
209006.91980595692,
235349.51827916596,
239300.03230287944,
210644.55183860307,
223486.28722687624,
239229.20488122758,
250128.32254601712,
215110.61133805048,
245745.34147894385,
310397.5946960565,
320338.89372197405,
]


def test_complete_year_as_one_block() -> None:
""" """
database, network = create_database_and_network(
HYDRO_MODEL_RULE_CURVES, return_to_initial_level=True
)

scenarios = 1
problem = build_problem(
network, database, TimeBlock(1, list(range(8736))), scenarios
)
problem.solver.EnableOutput()
status = problem.solver.Solve()
assert status == problem.solver.OPTIMAL
assert problem.solver.Objective().Value() == pytest.approx(57539807012)

output = OutputValues(problem)
generating = output.component("H").var("generating").value[0] # type:ignore
overflow = output.component("H").var("overflow").value[0] # type:ignore
assert output.component("H").var("level").value[0][ # type:ignore
-1
] == pytest.approx(0.445 * 1e7)
for week in range(52):
assert sum(
[
generating[t] + overflow[t] # type:ignore
for t in range(168 * week, 168 * (week + 1))
]
) == pytest.approx(optimal_generation[week])


def test_hydro_heuristic() -> None:
""" """
scenarios = 1
intermonthly_breakdown = 3
interdaily_breakdown = 3
folder_name = "hydro_with_rulecurves"

capacity = 1e7

for scenario in range(scenarios):
initial_level = 0.445 * capacity

initial_level, status, _, monthly_generation = optimize_target(
intermonthly_breakdown,
folder_name,
capacity,
scenario,
initial_level,
horizon="monthly",
timesteps=list(range(12)),
total_target=None,
)

assert status == pywraplp.Solver.OPTIMAL
assert monthly_generation == expected_monthly_generation

all_daily_generation: List[float] = []
day_in_year = 0

for month in range(12):
number_day_month = get_number_of_days_in_month(month)

(
initial_level,
status,
obj,
daily_generation,
) = optimize_target(
interdaily_breakdown,
folder_name,
capacity,
scenario,
initial_level,
horizon="daily",
timesteps=list(range(day_in_year, day_in_year + number_day_month)),
total_target=monthly_generation[month],
)

assert status == pywraplp.Solver.OPTIMAL

all_daily_generation = update_generation_target(
all_daily_generation, daily_generation
)
day_in_year += number_day_month

# Calcul des cibles hebdomadaires
weekly_target = calculate_weekly_target(
all_daily_generation,
)

# Vérification des valeurs trouvées
assert weekly_target == expected_weekly_target


def test_complete_year_as_weekly_blocks_with_hydro_heuristic() -> None:
""" """
database, network = create_database_and_network(
HYDRO_MODEL_WITH_TARGET, return_to_initial_level=False
)

capacity = 1e07
initial_level = 0.445 * capacity

total_cost = 0

scenarios = 1

for week in range(52):
database.add_data(
"H", "overall_target", ConstantData(expected_weekly_target[week])
)
database.add_data("H", "initial_level", ConstantData(initial_level))
problem = build_problem(
network,
database,
TimeBlock(1, list(range(168 * week, 168 * (week + 1)))),
scenarios,
)
status = problem.solver.Solve()
assert status == problem.solver.OPTIMAL
total_cost += problem.solver.Objective().Value()

output = OutputValues(problem)
initial_level = output.component("H").var("level").value[0][-1] # type:ignore

assert total_cost == pytest.approx(62994586218)


def create_database_and_network(
hydro_model: Model,
return_to_initial_level: bool,
) -> tuple[DataBase, Network]:
capacity = 1e07
initial_level = 0.445 * capacity
demand_data = np.loadtxt(
Path(__file__).parent
/ "../../tests/functional/data/hydro_with_rulecurves/load.txt",
usecols=0,
)
inflow_data = (
np.loadtxt(
Path(__file__).parent
/ "../../tests/functional/data/hydro_with_rulecurves/mod.txt",
usecols=0,
).repeat(24)
/ 24
)
rule_curve_data = np.loadtxt(
Path(__file__).parent
/ "../../tests/functional/data/hydro_with_rulecurves/reservoir.txt"
).repeat(24, axis=0)

node = Node(model=NODE_WITH_SPILL_AND_ENS_MODEL, id="1")

thermal_1 = create_component(
model=GENERATOR_MODEL,
id="G1",
)

thermal_2 = create_component(
model=GENERATOR_MODEL,
id="G2",
)

thermal_3 = create_component(
model=GENERATOR_MODEL,
id="G3",
)

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

hydro = create_component(model=hydro_model, id="H")

database = DataBase()

database.add_data("1", "spillage_cost", ConstantData(0))
database.add_data("1", "ens_cost", ConstantData(3000))
database.add_data(
"D",
"demand",
TimeSeriesData({TimeIndex(t): demand_data[t] for t in range(8760)}),
)

database.add_data(
"G1",
"p_max",
TimeSeriesData(
{TimeIndex(t): 20000 if 6000 <= t <= 7000 else 30000 for t in range(8760)}
),
)
database.add_data("G1", "cost", ConstantData(100))
database.add_data("G2", "p_max", ConstantData(12500))
database.add_data("G2", "cost", ConstantData(200))
database.add_data("G3", "p_max", ConstantData(7500))
database.add_data("G3", "cost", ConstantData(300))

database.add_data("H", "max_generating", ConstantData(50000))
database.add_data("H", "min_generating", ConstantData(-50000))
database.add_data("H", "capacity", ConstantData(capacity))
database.add_data("H", "initial_level", ConstantData(initial_level))

database.add_data(
"H",
"inflow",
TimeSeriesData({TimeIndex(t): inflow_data[t] for t in range(8760)}),
)

database.add_data(
"H",
"lower_rule_curve",
TimeSeriesData(
{
TimeIndex(i): rule_curve_data[(i - 1) % 8760][0] * capacity
for i in range(8760)
}
),
)
database.add_data(
"H",
"upper_rule_curve",
TimeSeriesData(
{
TimeIndex(i): rule_curve_data[(i - 1) % 8760][2] * capacity
for i in range(8760)
}
),
)

if return_to_initial_level:
database.add_data(
"H",
"max_epsilon",
ConstantData(0),
)
else:
database.add_data(
"H",
"max_epsilon",
TimeSeriesData(
{TimeIndex(i): capacity if i % 168 == 0 else 0 for i in range(8760)}
),
)

network = Network("test")
network.add_node(node)
network.add_component(demand)
network.add_component(thermal_1)
network.add_component(thermal_2)
network.add_component(thermal_3)
network.add_component(hydro)
network.connect(PortRef(node, "balance_port"), PortRef(demand, "balance_port"))
network.connect(PortRef(node, "balance_port"), PortRef(thermal_1, "balance_port"))
network.connect(PortRef(node, "balance_port"), PortRef(thermal_2, "balance_port"))
network.connect(PortRef(node, "balance_port"), PortRef(thermal_3, "balance_port"))
network.connect(PortRef(node, "balance_port"), PortRef(hydro, "balance_port"))
return database, network