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

refactor(hydro): create user class #82

Draft
wants to merge 40 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
532acb6
move services
MartinBelthle Feb 11, 2025
76b1cc1
continue work
MartinBelthle Feb 11, 2025
752e412
continue work
MartinBelthle Feb 11, 2025
60c3a4b
fix issues
MartinBelthle Feb 11, 2025
9e41441
add todos
MartinBelthle Feb 11, 2025
a197db5
add aliases
MartinBelthle Feb 11, 2025
45307f5
refacto
MartinBelthle Feb 11, 2025
6ec4d3f
remove matrices from object
MartinBelthle Feb 11, 2025
42920f6
add todo
MartinBelthle Feb 11, 2025
4c0053e
continue work
MartinBelthle Feb 12, 2025
a936d19
fix
MartinBelthle Feb 12, 2025
47b56d4
continue
MartinBelthle Feb 12, 2025
570f932
continue
MartinBelthle Feb 12, 2025
e5ad7ff
add methods
MartinBelthle Feb 12, 2025
2ebd736
continue refactor
MartinBelthle Feb 12, 2025
3dafd6a
continue work
MartinBelthle Feb 12, 2025
b2b2e82
continue work
MartinBelthle Feb 12, 2025
0f8f6ea
ddfd
MartinBelthle Feb 12, 2025
2047b62
ddfd
MartinBelthle Feb 12, 2025
758068d
introduce everything
MartinBelthle Feb 12, 2025
e65ac44
merge with main
MartinBelthle Feb 12, 2025
63726e4
move models inside base_model classes
MartinBelthle Feb 12, 2025
e5f536e
dsfdsf
MartinBelthle Feb 12, 2025
f1baf20
use default values
MartinBelthle Feb 12, 2025
29935c0
fix test
MartinBelthle Feb 12, 2025
011ce48
refac
MartinBelthle Feb 12, 2025
b92d566
remove optional
MartinBelthle Feb 12, 2025
70037ab
little fix
MartinBelthle Feb 12, 2025
a314b71
ehe
MartinBelthle Feb 12, 2025
f0b07e9
3 test failing
MartinBelthle Feb 12, 2025
c360c53
sort values
MartinBelthle Feb 12, 2025
a984dd6
fsf
MartinBelthle Feb 12, 2025
658dc97
alo
MartinBelthle Feb 12, 2025
a70324e
al
MartinBelthle Feb 12, 2025
dba37e1
create matix
MartinBelthle Feb 12, 2025
fb61f03
3 tests failing
MartinBelthle Feb 12, 2025
378d2aa
final test failing
MartinBelthle Feb 12, 2025
3960432
implement
MartinBelthle Feb 12, 2025
63bb82a
yeah
MartinBelthle Feb 12, 2025
2717302
cleaning
MartinBelthle Feb 12, 2025
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
12 changes: 12 additions & 0 deletions src/antares/craft/exceptions/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,18 @@ def __init__(self, area_id: str, message: str) -> None:
super().__init__(self.message)


class HydroPropertiesUpdateError(Exception):
def __init__(self, area_id: str, message: str) -> None:
self.message = f"Could not update hydro properties for area {area_id}: " + message
super().__init__(self.message)


class HydroPropertiesReadingError(Exception):
def __init__(self, area_id: str, message: str) -> None:
self.message = f"Could not read hydro properties for area {area_id}: " + message
super().__init__(self.message)


class RenewableCreationError(Exception):
def __init__(self, renewable_name: str, area_id: str, message: str) -> None:
self.message = f"Could not create the renewable cluster {renewable_name} inside area {area_id}: " + message
Expand Down
21 changes: 3 additions & 18 deletions src/antares/craft/model/area.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import pandas as pd

from antares.craft.model.commons import FilterOption, sort_filter_values
from antares.craft.model.hydro import Hydro, HydroMatrixName, HydroProperties
from antares.craft.model.hydro import Hydro, HydroProperties
from antares.craft.model.renewable import RenewableCluster, RenewableClusterProperties
from antares.craft.model.st_storage import STStorage, STStorageProperties
from antares.craft.model.thermal import ThermalCluster, ThermalClusterProperties
Expand Down Expand Up @@ -222,7 +222,7 @@ def __init__(
self._renewables = renewables or dict()
self._thermals = thermals or dict()
self._st_storages = st_storages or dict()
self._hydro = hydro
self._hydro = hydro or Hydro(self._hydro_service, self._id, HydroProperties())
self._properties = properties or AreaProperties()
self._ui = ui or AreaUi()

Expand All @@ -244,7 +244,7 @@ def get_st_storages(self) -> MappingProxyType[str, STStorage]:
return MappingProxyType(self._st_storages)

@property
def hydro(self) -> Optional[Hydro]:
def hydro(self) -> Hydro:
return self._hydro

@property
Expand Down Expand Up @@ -346,16 +346,6 @@ def create_solar(self, series: pd.DataFrame) -> None:
def create_misc_gen(self, series: pd.DataFrame) -> None:
self._area_service.create_misc_gen(self.id, series)

def create_hydro(
self,
properties: Optional[HydroProperties] = None,
matrices: Optional[dict[HydroMatrixName, pd.DataFrame]] = None,
) -> Hydro:
# todo: is it necessary to create allocation or correlation ?
hydro = self._area_service.create_hydro(self.id, properties, matrices)
self._hydro = hydro
return hydro

def read_st_storages(
self,
) -> list[STStorage]:
Expand All @@ -370,8 +360,3 @@ def read_thermal_clusters(
self,
) -> list[ThermalCluster]:
return self._thermal_service.read_thermal_clusters(self.id)

def read_hydro(
self,
) -> Hydro:
return self._area_service.read_hydro(self.id)
118 changes: 63 additions & 55 deletions src/antares/craft/model/hydro.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,13 @@
# SPDX-License-Identifier: MPL-2.0
#
# This file is part of the Antares project.

from dataclasses import dataclass
from enum import Enum
from typing import Optional

import pandas as pd

from antares.craft.service.base_services import BaseHydroService
from antares.craft.tools.all_optional_meta import all_optional_model
from pydantic import BaseModel
from pydantic.alias_generators import to_camel


class HydroMatrixName(Enum):
Expand All @@ -33,13 +30,27 @@ class HydroMatrixName(Enum):
COMMON_CREDIT_MODULATIONS = "creditmodulations"


class DefaultHydroProperties(BaseModel, extra="forbid", populate_by_name=True, alias_generator=to_camel):
"""
Properties of hydro system read from the configuration files.

All aliases match the name of the corresponding field in the INI files.
"""

@dataclass
class HydroPropertiesUpdate:
inter_daily_breakdown: Optional[float] = None
intra_daily_modulation: Optional[float] = None
inter_monthly_breakdown: Optional[float] = None
reservoir: Optional[bool] = None
reservoir_capacity: Optional[float] = None
follow_load: Optional[bool] = None
use_water: Optional[bool] = None
hard_bounds: Optional[bool] = None
initialize_reservoir_date: Optional[int] = None
use_heuristic: Optional[bool] = None
power_to_level: Optional[bool] = None
use_leeway: Optional[bool] = None
leeway_low: Optional[float] = None
leeway_up: Optional[float] = None
pumping_efficiency: Optional[float] = None


@dataclass
class HydroProperties:
inter_daily_breakdown: float = 1
intra_daily_modulation: float = 24
inter_monthly_breakdown: float = 1
Expand All @@ -56,64 +67,46 @@ class DefaultHydroProperties(BaseModel, extra="forbid", populate_by_name=True, a
leeway_up: float = 1
pumping_efficiency: float = 1


@all_optional_model
class HydroProperties(DefaultHydroProperties):
pass


class HydroPropertiesLocal(DefaultHydroProperties):
area_id: str

@property
def hydro_ini_fields(self) -> dict[str, dict[str, str]]:
return {
"inter-daily-breakdown": {f"{self.area_id}": f"{self.inter_daily_breakdown:.6f}"},
"intra-daily-modulation": {f"{self.area_id}": f"{self.intra_daily_modulation:.6f}"},
"inter-monthly-breakdown": {f"{self.area_id}": f"{self.inter_monthly_breakdown:.6f}"},
"reservoir": {f"{self.area_id}": f"{self.reservoir}".lower()},
"reservoir capacity": {f"{self.area_id}": f"{self.reservoir_capacity:.6f}"},
"follow load": {f"{self.area_id}": f"{self.follow_load}".lower()},
"use water": {f"{self.area_id}": f"{self.use_water}".lower()},
"hard bounds": {f"{self.area_id}": f"{self.hard_bounds}".lower()},
"initialize reservoir date": {f"{self.area_id}": f"{self.initialize_reservoir_date}"},
"use heuristic": {f"{self.area_id}": f"{self.use_heuristic}".lower()},
"power to level": {f"{self.area_id}": f"{self.power_to_level}".lower()},
"use leeway": {f"{self.area_id}": f"{self.use_leeway}".lower()},
"leeway low": {f"{self.area_id}": f"{self.leeway_low:.6f}"},
"leeway up": {f"{self.area_id}": f"{self.leeway_up:.6f}"},
"pumping efficiency": {f"{self.area_id}": f"{self.pumping_efficiency:.6f}"},
}

def yield_hydro_properties(self) -> HydroProperties:
excludes = {"area_id", "hydro_ini_fields"}
return HydroProperties.model_validate(self.model_dump(mode="json", exclude=excludes))
def to_update_properties(self) -> HydroPropertiesUpdate:
return HydroPropertiesUpdate(
inter_daily_breakdown=self.inter_daily_breakdown,
intra_daily_modulation=self.intra_daily_modulation,
inter_monthly_breakdown=self.inter_monthly_breakdown,
reservoir=self.reservoir,
reservoir_capacity=self.reservoir_capacity,
follow_load=self.follow_load,
use_water=self.use_water,
hard_bounds=self.hard_bounds,
initialize_reservoir_date=self.initialize_reservoir_date,
use_heuristic=self.use_heuristic,
power_to_level=self.power_to_level,
use_leeway=self.use_leeway,
leeway_low=self.leeway_low,
leeway_up=self.leeway_up,
pumping_efficiency=self.pumping_efficiency,
)


class Hydro:
def __init__(
self,
service: BaseHydroService,
area_id: str,
properties: Optional[HydroProperties] = None,
matrices: Optional[dict[HydroMatrixName, pd.DataFrame]] = None,
):
def __init__(self, service: BaseHydroService, area_id: str, properties: HydroProperties):
self._area_id = area_id
self._service = service
self._properties = properties
self._matrices = matrices

@property
def area_id(self) -> str:
return self._area_id

@property
def properties(self) -> Optional[HydroProperties]:
def properties(self) -> HydroProperties:
return self._properties

@property
def matrices(self) -> Optional[dict[HydroMatrixName, pd.DataFrame]]:
return self._matrices
def update_properties(self, properties: HydroPropertiesUpdate) -> None:
self._service.update_properties(self.area_id, properties)
self._properties = self.read_properties()

def read_properties(self) -> HydroProperties:
return self._service.read_properties(self.area_id)

def get_maxpower(self) -> pd.DataFrame:
return self._service.get_maxpower(self.area_id)
Expand All @@ -129,3 +122,18 @@ def get_credit_modulations(self) -> pd.DataFrame:

def get_water_values(self) -> pd.DataFrame:
return self._service.get_water_values(self.area_id)

def update_maxpower(self, series: pd.DataFrame) -> None:
return self._service.update_maxpower(self.area_id, series)

def update_reservoir(self, series: pd.DataFrame) -> None:
return self._service.update_reservoir(self.area_id, series)

def update_inflow_pattern(self, series: pd.DataFrame) -> None:
return self._service.update_inflow_pattern(self.area_id, series)

def update_credits_modulation(self, series: pd.DataFrame) -> None:
return self._service.update_credits_modulation(self.area_id, series)

def update_water_values(self, series: pd.DataFrame) -> None:
return self._service.update_water_values(self.area_id, series)
68 changes: 8 additions & 60 deletions src/antares/craft/service/api_services/area_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
AreaPropertiesUpdateError,
AreasRetrievalError,
AreaUiUpdateError,
HydroCreationError,
MatrixDownloadError,
MatrixUploadError,
RenewableCreationError,
Expand All @@ -34,7 +33,7 @@
ThermalDeletionError,
)
from antares.craft.model.area import Area, AreaProperties, AreaUi
from antares.craft.model.hydro import Hydro, HydroMatrixName, HydroProperties
from antares.craft.model.hydro import Hydro
from antares.craft.model.renewable import RenewableCluster, RenewableClusterProperties
from antares.craft.model.st_storage import STStorage, STStorageProperties
from antares.craft.model.thermal import ThermalCluster, ThermalClusterProperties
Expand All @@ -48,7 +47,7 @@
BaseShortTermStorageService,
BaseThermalService,
)
from antares.craft.tools.contents_tool import AreaUiResponse
from antares.craft.tools.contents_tool import AreaUiResponse, transform_name_to_id
from antares.craft.tools.matrix_tool import prepare_args_replace_matrix
from typing_extensions import override

Expand Down Expand Up @@ -131,7 +130,8 @@ def create_area(
ui_response = AreaUiResponse.model_validate(json_ui)
ui_properties = AreaUi.model_validate(ui_response.to_craft())

hydro = self.read_hydro(area_id)
hydro_properties = self.hydro_service.read_properties(area_id)
hydro = Hydro(self.hydro_service, area_id, hydro_properties)

except APIError as e:
raise AreaCreationError(area_name, e.message) from e
Expand Down Expand Up @@ -352,62 +352,6 @@ def create_misc_gen(self, area_id: str, series: pd.DataFrame) -> None:
except APIError as e:
raise MatrixUploadError(area_id, "misc-gen", e.message) from e

@override
def create_hydro(
self,
area_id: str,
properties: Optional[HydroProperties],
matrices: Optional[dict[HydroMatrixName, pd.DataFrame]],
) -> Hydro:
# todo: not model validation because endpoint does not return anything
# properties = HydroProperties.model_validate(json_response) not possible

try:
url = f"{self._base_url}/studies/{self.study_id}/areas/{area_id}/hydro/form"
body = {}
if properties:
camel_properties = properties.model_dump(mode="json", by_alias=True, exclude_none=True)
body = {**camel_properties}
self._wrapper.put(url, json=body)

if matrices is not None:
self._create_hydro_series(area_id, matrices)

except APIError as e:
raise HydroCreationError(area_id, e.message) from e

return Hydro(self.hydro_service, area_id, properties)

@override
def read_hydro(
self,
area_id: str,
) -> Hydro:
url = f"{self._base_url}/studies/{self.study_id}/areas/{area_id}/hydro/form"
json_hydro = self._wrapper.get(url).json()

hydro_props = HydroProperties(**json_hydro)
hydro = Hydro(self.hydro_service, area_id, hydro_props)

return hydro

def _create_hydro_series(self, area_id: str, matrices: dict[HydroMatrixName, pd.DataFrame]) -> None:
command_body = []
for matrix_name, series in matrices.items():
if "SERIES" in matrix_name.name:
series_path = f"input/hydro/series/{area_id}/{matrix_name.value}"
command_body.append(prepare_args_replace_matrix(series, series_path))
if "PREPRO" in matrix_name.name:
series_path = f"input/hydro/prepro/{area_id}/{matrix_name.value}"
command_body.append(prepare_args_replace_matrix(series, series_path))
if "COMMON" in matrix_name.name:
series_path = f"input/hydro/common/capacity/{matrix_name.value}_{area_id}"
command_body.append(prepare_args_replace_matrix(series, series_path))
if command_body:
json_payload = command_body

self._replace_matrix_request(json_payload)

@override
def update_area_properties(self, area_id: str, properties: AreaProperties) -> AreaProperties:
url = f"{self._base_url}/studies/{self.study_id}/areas/{area_id}/properties/form"
Expand Down Expand Up @@ -563,6 +507,9 @@ def read_areas(self) -> list[Area]:
dict_thermals = {thermal.id: thermal for thermal in thermals}
dict_st_storage = {storage.id: storage for storage in st_storages}

area_id = transform_name_to_id(area)
hydro_properties = self.hydro_service.read_properties(area_id)
hydro = Hydro(self.hydro_service, area_id, hydro_properties)
area_obj = Area(
area,
self,
Expand All @@ -575,6 +522,7 @@ def read_areas(self) -> list[Area]:
st_storages=dict_st_storage,
properties=json_properties,
ui=ui_response,
hydro=hydro,
)

area_list.append(area_obj)
Expand Down
Loading
Loading