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

Thermal heuristic #45

Open
wants to merge 93 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
d2b46d2
Add first tests on thermal heuristics
May 28, 2024
24700f4
Implement accurate heuristic on simple problem
May 28, 2024
fd3a884
Add comments
May 28, 2024
0a6d4df
Add fast heuristic and improve accurate
May 31, 2024
c703040
rename test heuristic
May 31, 2024
9db4b54
Implement complex model
May 31, 2024
83360de
Accurate for complex model
May 31, 2024
bde9904
Type errors and useless solver parameters
Jun 4, 2024
4bfd696
check hourly outputs
Jun 4, 2024
3427eb4
fast heuristic for complex case
Jun 4, 2024
c79ba8f
Test for 2 weeks
Jun 5, 2024
dd61b8d
Test for 2 scenarios
Jun 6, 2024
5cb88db
add test for scenarios
Jun 7, 2024
9a9ec8d
Add more details on tests concerning scenarios
Jun 10, 2024
1be8483
Add milp test for second case
Jun 12, 2024
96fa166
remove milp test
Jun 13, 2024
add82e9
Add test accurate for second test case
Jun 13, 2024
40282a0
Add fast test for second test case
Jun 13, 2024
5700856
convert fast to optimization problem
Jun 5, 2024
dcd2c47
Optimization problem for fast on simple case
Jun 17, 2024
ea55b7d
Optimization model fast complex case
Jun 18, 2024
25bddc0
Small corrections
Jun 18, 2024
db17284
Correct test
Jun 18, 2024
6cf6611
Optimization problem heuristic fast second complex test case
Jun 18, 2024
3d9cb5b
Equivalent solution for fast heuristic optimization
Jun 21, 2024
57e5f7c
Api for fast and accurate models
Jun 25, 2024
e828f65
Api for accurate heuristic model
Jun 25, 2024
78a4712
Move models to library
Jun 26, 2024
0b10902
Move some functions from tests to src
Jun 27, 2024
912f083
Remove all functions from simple test
Jun 27, 2024
5b5c2b0
Move functions from second complex test to src
Jun 27, 2024
412e62c
Remove functions from second test and filter ts on scenarios and time…
Jun 28, 2024
e4fc78a
Sort imports
Jun 28, 2024
282c0f3
Run black
Jun 28, 2024
547ba3c
Change solver to fix tests in the ci
Jun 28, 2024
3f3d09f
Fix ci
Jun 28, 2024
6061ffe
Rename tests
Jun 28, 2024
e7c4cbe
Generalize check_output
Jul 2, 2024
8067cc8
More tests on data
Jul 2, 2024
c1408fa
Refactor model
Jul 3, 2024
17c76e6
Refactor problem.py
Jul 3, 2024
0ad6401
Generic database
Jul 3, 2024
54c93c0
Correct error
Jul 3, 2024
585fc50
Create ThermalProblemBuilder
Jul 4, 2024
ec850d8
Resolution steps
Jul 4, 2024
a3325e7
Simplify get_value out of database
Jul 4, 2024
5fadf5d
Simplify update of database
Jul 8, 2024
f259b55
Fix ci
Jul 8, 2024
f59285c
Remove not used imports
Jul 8, 2024
b6ec938
New test
Jul 15, 2024
38aafbb
Small changes
Jul 15, 2024
627aeb2
New test with bc
Jul 15, 2024
a5dcb1f
Refactoring
Jul 30, 2024
2915a19
Exhibit models
Aug 1, 2024
8663444
Remove unused imports
Aug 2, 2024
945c58d
New class for time scenario parameters
Aug 2, 2024
8a42060
Refactor solve
Aug 2, 2024
c88263c
Sort imports
Aug 2, 2024
3fbfa5d
Formating
Aug 2, 2024
8a0fe98
Refactor data_path
Aug 2, 2024
dec3bd5
Fix test
Aug 2, 2024
8ed1d47
Refactor models
Aug 2, 2024
042fc12
Fix test
Aug 2, 2024
e099b75
Run isort
Aug 2, 2024
f1f08e8
Week scenario parameters
Aug 2, 2024
d5f1535
Refactor solve
Aug 2, 2024
296f532
Rename functions
Aug 5, 2024
cb14787
Refactor cluster parameters
Aug 5, 2024
1d2f622
Correct error
Aug 5, 2024
c2abe5a
Refactor update
Aug 5, 2024
9a4ddbe
New test
Aug 7, 2024
75df4fd
New test with ramp
Aug 8, 2024
1d0da2c
Refactor
Aug 9, 2024
d2334fe
Add description for tests
Aug 9, 2024
137dc77
Beginning of new test
Aug 20, 2024
0329ffa
Improve edit_value
Aug 20, 2024
4b7bb35
Improve cluster parameters
Aug 20, 2024
d9831be
Move expected_output class
Aug 20, 2024
270200b
Change names
Aug 20, 2024
bb36d38
Remove network and database building from thermal_problem_builder
Aug 20, 2024
3c694b4
Correct pytest fixture
Aug 20, 2024
580ddcc
Remove solve from thermal problem builder
Aug 20, 2024
2c9a765
Fix test
Aug 20, 2024
1aebb07
Move tests
Aug 20, 2024
9ce1fd5
Improve test with parameters
Aug 21, 2024
5a57bcb
Use data_path
Aug 21, 2024
b4790ce
Improve pytest fixture
Aug 21, 2024
35a2f64
Improve tests
Aug 21, 2024
a34780f
Fix ci
Aug 26, 2024
a4534e7
Fix tests
Aug 26, 2024
b039478
Fix test on day ahead reserve
Aug 29, 2024
9a68f0e
Unused code
Sep 6, 2024
f9f5134
api file
Oct 24, 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
29 changes: 21 additions & 8 deletions src/andromede/simulation/optimization.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from abc import ABC, abstractmethod
from dataclasses import dataclass
from enum import Enum
from typing import Dict, Iterable, List, Optional, Type
from typing import Dict, Iterable, List, Optional, Type, Union

import ortools.linear_solver.pywraplp as lp

Expand Down Expand Up @@ -68,8 +68,9 @@ def _get_parameter_value(
name: str,
) -> float:
data = context.database.get_data(component_id, name)
absolute_scenario = context.scenario_to_absolute_scenario(scenario)
absolute_timestep = context.block_timestep_to_absolute_timestep(block_timestep)
return data.get_value(absolute_timestep, scenario)
return data.get_value(absolute_timestep, absolute_scenario)


# TODO: Maybe add the notion of constant parameter in the model
Expand Down Expand Up @@ -303,7 +304,7 @@ def __init__(
network: Network,
database: DataBase,
block: TimeBlock,
scenarios: int,
scenarios: Union[List[int], int],
border_management: BlockBorderManagement,
):
self._network = network
Expand All @@ -322,9 +323,16 @@ def network(self) -> Network:
return self._network

@property
def scenarios(self) -> int:
def scenarios(self) -> Union[List[int], int]:
Juliette-Gerbaux marked this conversation as resolved.
Show resolved Hide resolved
return self._scenarios

def scenario_length(self) -> int:
if type(self.scenarios) is int:
Juliette-Gerbaux marked this conversation as resolved.
Show resolved Hide resolved
return self.scenarios
elif type(self.scenarios) is List:
return len(self.scenarios)
return 1

def block_length(self) -> int:
return len(self._block.timesteps)

Expand All @@ -336,6 +344,11 @@ def connection_fields_expressions(self) -> Dict[PortFieldKey, List[ExpressionNod
def block_timestep_to_absolute_timestep(self, block_timestep: int) -> int:
return self._block.timesteps[block_timestep]

def scenario_to_absolute_scenario(self, scenario: int) -> int:
if type(self.scenarios) is List or type(self.scenarios) is list:
return self.scenarios[scenario]
return scenario

@property
def database(self) -> DataBase:
return self._database
Expand All @@ -350,7 +363,7 @@ def get_time_indices(self, index_structure: IndexingStructure) -> Iterable[int]:
return range(self.block_length()) if index_structure.time else range(1)

def get_scenario_indices(self, index_structure: IndexingStructure) -> Iterable[int]:
return range(self.scenarios) if index_structure.scenario else range(1)
return range(self.scenario_length()) if index_structure.scenario else range(1)

# TODO: API to improve, variable_structure guides which of the indices block_timestep and scenario should be used
def get_component_variable(
Expand Down Expand Up @@ -508,8 +521,8 @@ def _create_objective(
for term in linear_expr.terms.values():
# TODO : How to handle the scenario operator in a general manner ?
if isinstance(term.scenario_operator, Expectation):
weight = 1 / opt_context.scenarios
scenario_ids = range(opt_context.scenarios)
weight = 1 / opt_context.scenario_length()
scenario_ids = range(opt_context.scenario_length())
else:
weight = 1
scenario_ids = range(1)
Expand Down Expand Up @@ -819,7 +832,7 @@ def build_problem(
network: Network,
database: DataBase,
block: TimeBlock,
scenarios: int,
scenarios: Union[List[int], int],
*,
problem_name: str = "optimization_problem",
border_management: BlockBorderManagement = BlockBorderManagement.CYCLE,
Expand Down
55 changes: 54 additions & 1 deletion src/andromede/study/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from abc import ABC, abstractmethod
from dataclasses import dataclass
from pathlib import Path
from typing import Dict, Optional
from typing import Dict, List, Optional

import pandas as pd

Expand Down Expand Up @@ -41,6 +41,12 @@ class AbstractDataStructure(ABC):
def get_value(self, timestep: int, scenario: int) -> float:
return NotImplemented

def set_value(self, value: float, timestep: int, scenario: int) -> None:
raise NotImplementedError

def get_max_value(self) -> float:
return NotImplemented

@abstractmethod
def check_requirement(self, time: bool, scenario: bool) -> bool:
"""
Expand All @@ -57,6 +63,9 @@ class ConstantData(AbstractDataStructure):
def get_value(self, timestep: int, scenario: int) -> float:
return self.value

def get_max_value(self) -> float:
return self.value

# ConstantData can be used for time varying or constant models
def check_requirement(self, time: bool, scenario: bool) -> bool:
if not isinstance(self, ConstantData):
Expand All @@ -77,6 +86,12 @@ class TimeSeriesData(AbstractDataStructure):
def get_value(self, timestep: int, scenario: int) -> float:
return self.time_series[TimeIndex(timestep)]

def set_value(self, value: float, timestep: int, scenario: int) -> None:
self.time_series[TimeIndex(timestep)] = value

def get_max_value(self) -> float:
return max(self.time_series.values())

def check_requirement(self, time: bool, scenario: bool) -> bool:
if not isinstance(self, TimeSeriesData):
raise ValueError("Invalid data type for TimeSeriesData")
Expand All @@ -97,6 +112,12 @@ class ScenarioSeriesData(AbstractDataStructure):
def get_value(self, timestep: int, scenario: int) -> float:
return self.scenario_series[ScenarioIndex(scenario)]

def set_value(self, value: float, timestep: int, scenario: int) -> None:
self.scenario_series[ScenarioIndex(scenario)] = value

def get_max_value(self) -> float:
return max(self.scenario_series.values())

def check_requirement(self, time: bool, scenario: bool) -> bool:
if not isinstance(self, ScenarioSeriesData):
raise ValueError("Invalid data type for TimeSeriesData")
Expand Down Expand Up @@ -130,6 +151,12 @@ def get_value(self, timestep: int, scenario: int) -> float:
value = str(self.time_scenario_series.iloc[timestep, scenario])
return float(value)

def set_value(self, value: float, timestep: int, scenario: int) -> None:
self.time_scenario_series.iloc[timestep, scenario] = value

def get_max_value(self) -> float:
return self.time_scenario_series.values.max()

def check_requirement(self, time: bool, scenario: bool) -> bool:
if not isinstance(self, TimeScenarioSeriesData):
raise ValueError("Invalid data type for TimeScenarioSeriesData")
Expand Down Expand Up @@ -172,6 +199,18 @@ def get_value(
else:
raise KeyError(f"Index {index} not found.")

def set_value(
self, index: ComponentParameterIndex, value: float, timestep: int, scenario: int
) -> None:
self._data[index].set_value(value, timestep, scenario)

def convert_to_time_scenario_series_data(
self, index: ComponentParameterIndex, timesteps: int, scenarios: int
) -> None:
self._data[index] = convert_to_time_scenario_series_data(
self._data[index], timesteps, scenarios
)

def requirements_consistency(self, network: Network) -> None:
for component in network.components:
for param in component.model.parameters.values():
Expand All @@ -184,3 +223,17 @@ def requirements_consistency(self, network: Network) -> None:
raise ValueError(
f"Data inconsistency for component: {component.id}, parameter: {param.name}. Requirement not met."
)


def convert_to_time_scenario_series_data(
Juliette-Gerbaux marked this conversation as resolved.
Show resolved Hide resolved
initial_data: AbstractDataStructure, timesteps: int, scenarios: int
) -> TimeScenarioSeriesData:
data = pd.DataFrame(
[
[initial_data.get_value(t, s) for s in range(scenarios)]
for t in range(timesteps)
],
index=list(range(timesteps)),
columns=list(range(scenarios)),
)
return TimeScenarioSeriesData(data)
2 changes: 1 addition & 1 deletion src/andromede/study/resolve_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def build_data_base(
input_comp: InputComponents, timeseries_dir: Optional[Path]
) -> DataBase:
database = DataBase()
for comp in input_comp.components:
for comp in input_comp.components + input_comp.nodes:
for param in comp.parameters or []:
param_value = _evaluate_param_type(
param.type, param.value, param.timeseries, timeseries_dir
Expand Down
Loading
Loading