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
Show file tree
Hide file tree
Changes from all commits
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
248 changes: 248 additions & 0 deletions src/andromede/hydro_heuristic/data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
# 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 dataclasses import dataclass
from typing import List, Optional

import numpy as np
import pandas as pd

from andromede.study import (
ConstantData,
DataBase,
TimeIndex,
TimeScenarioSeriesData,
TimeSeriesData,
)


@dataclass(frozen=False)
class ReservoirParameters:
capacity: float
initial_level: float
folder_name: str
scenario: int


@dataclass(frozen=True)
class HydroHeuristicParameters:
inter_breakdown: int = 1
total_target: Optional[float] = None


@dataclass(frozen=True)
class DataAggregatorParameters:
hours_aggregated_time_steps: List[int]
timesteps: List[int]


@dataclass(frozen=True)
class RawDataProperties:
name_file: str
column: int
hours_input: int


def get_number_of_days_in_month(month: int) -> int:
number_day_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]
return number_day_month


class RawHydroData:
def __init__(self, folder_name: str, scenario: int) -> None:
self.folder_name = folder_name
self.scenario = scenario

self.properties = {
"demand": RawDataProperties("load", self.scenario, 1),
"inflow": RawDataProperties("mod", self.scenario, 24),
"lower_rule_curve": RawDataProperties("reservoir", 0, 24),
"upper_rule_curve": RawDataProperties("reservoir", 2, 24),
"max_generating": RawDataProperties("maxpower", 0, 24),
}

def read_data(self, name: str) -> List[float]:
properties = self.properties[name]
data = np.loadtxt(f"{self.folder_name}/{properties.name_file}.txt")
if len(data.shape) >= 2:
data = data[:, properties.column]
hourly_data = self.convert_to_hourly_data(properties, list(data))

return hourly_data

def convert_to_hourly_data(
self, properties: RawDataProperties, data: List[float]
) -> List[float]:
hourly_data = np.repeat(np.array(data), properties.hours_input)
if properties.name_file == "mod":
hourly_data = hourly_data / properties.hours_input
return list(hourly_data)


class HydroHeuristicData:
def __init__(
self,
data_aggregator_parameters: DataAggregatorParameters,
reservoir_data: ReservoirParameters,
):
self.reservoir_data = reservoir_data

data_aggregator = DataAggregator(
data_aggregator_parameters,
)

raw_data_reader = RawHydroData(
reservoir_data.folder_name, reservoir_data.scenario
)

self.demand = data_aggregator.aggregate_data(
operator="sum",
data=raw_data_reader.read_data("demand"),
)
self.inflow = data_aggregator.aggregate_data(
operator="sum",
data=raw_data_reader.read_data("inflow"),
)
self.lower_rule_curve = data_aggregator.aggregate_data(
operator="lag_first_element",
data=raw_data_reader.read_data("lower_rule_curve"),
)
self.upper_rule_curve = data_aggregator.aggregate_data(
operator="lag_first_element",
data=raw_data_reader.read_data("upper_rule_curve"),
)
self.max_generating = data_aggregator.aggregate_data(
operator="sum",
data=raw_data_reader.read_data("max_generating"),
)

def compute_target(self, heuristic_parameters: HydroHeuristicParameters) -> None:
if heuristic_parameters.total_target is None:
total_target = sum(self.inflow)
else:
total_target = heuristic_parameters.total_target
target = (
total_target
* np.power(self.demand, heuristic_parameters.inter_breakdown)
/ sum(np.power(self.demand, heuristic_parameters.inter_breakdown))
)

self.target = list(target)


@dataclass(frozen=True)
class DataAggregator:
data_aggregator_parameters: DataAggregatorParameters

def aggregate_data(self, operator: str, data: List[float]) -> List[float]:
aggregated_data: List[float] = []
hour = 0
for time_step, hours_time_step in enumerate(
self.data_aggregator_parameters.hours_aggregated_time_steps
):
if time_step in self.data_aggregator_parameters.timesteps:
if operator == "sum":
aggregated_data.append(np.sum(data[hour : hour + hours_time_step]))
elif operator == "lag_first_element":
aggregated_data.append(data[(hour + hours_time_step) % len(data)])
hour += hours_time_step
return aggregated_data


def save_generation_target(
all_daily_generation: List[float], daily_generation: List[float]
) -> List[float]:
all_daily_generation = all_daily_generation + daily_generation
return all_daily_generation


def compute_weekly_target(all_daily_generation: List[float]) -> List[float]:
weekly_target = [
sum([all_daily_generation[day] for day in range(7 * week, 7 * (week + 1))])
for week in range(len(all_daily_generation) // 7)
]

return weekly_target


def get_database(hydro_data: HydroHeuristicData, id: str = "H") -> DataBase:
database = DataBase()

database.add_data(id, "capacity", ConstantData(hydro_data.reservoir_data.capacity))
database.add_data(
id,
"initial_level",
ConstantData(hydro_data.reservoir_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(id, "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(id, "generating_target", TimeScenarioSeriesData(target_data))
database.add_data(id, "overall_target", ConstantData(sum(hydro_data.target)))

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

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

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

return database
Loading
Loading