Skip to content

Commit

Permalink
fix(local): add missing files at area and thermal creation (#58)
Browse files Browse the repository at this point in the history
* Add missing files for create area and thermal cluster in local

* Add licences for new tests files

* Add licences for new tests files
  • Loading branch information
vargastat authored Jan 22, 2025
1 parent 768a5c8 commit 5f35882
Show file tree
Hide file tree
Showing 14 changed files with 677 additions and 494 deletions.
8 changes: 4 additions & 4 deletions src/antares/craft/model/study.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
from antares.craft.service.api_services.study_api import _returns_study_settings
from antares.craft.service.base_services import BaseStudyService
from antares.craft.service.service_factory import ServiceFactory
from antares.craft.tools.ini_tool import IniFile, IniFileTypes
from antares.craft.tools.ini_tool import IniFile, InitializationFilesTypes

"""
The study module defines the data model for antares study.
Expand Down Expand Up @@ -140,7 +140,7 @@ def create_study_local(
desktop_ini_file.write(desktop_ini_content)

local_settings = StudySettingsLocal.model_validate(settings)
local_settings_file = IniFile(study_directory, IniFileTypes.GENERAL)
local_settings_file = IniFile(study_directory, InitializationFilesTypes.GENERAL)
local_settings_file.ini_dict = local_settings.model_dump(exclude_none=True, by_alias=True)
local_settings_file.write_ini_file()

Expand Down Expand Up @@ -174,7 +174,7 @@ def _directory_not_exists(local_path: Path) -> None:

_directory_not_exists(study_directory)

study_antares = IniFile(study_directory, IniFileTypes.ANTARES)
study_antares = IniFile(study_directory, InitializationFilesTypes.ANTARES)

study_params = study_antares.ini_dict["antares"]

Expand Down Expand Up @@ -480,7 +480,7 @@ def _create_correlation_ini_files(local_settings: StudySettingsLocal, study_dire
correlation_inis_to_create = [
(
field + "_correlation",
getattr(IniFileTypes, field.upper() + "_CORRELATION_INI"),
getattr(InitializationFilesTypes, field.upper() + "_CORRELATION_INI"),
field,
)
for field in fields_to_check
Expand Down
41 changes: 29 additions & 12 deletions src/antares/craft/service/local_services/area_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
BaseThermalService,
)
from antares.craft.tools.contents_tool import transform_name_to_id
from antares.craft.tools.ini_tool import IniFile, IniFileTypes
from antares.craft.tools.ini_tool import IniFile, InitializationFilesTypes
from antares.craft.tools.matrix_tool import read_timeseries
from antares.craft.tools.prepro_folder import PreproFolder
from antares.craft.tools.time_series_tool import TimeSeriesFileType
Expand Down Expand Up @@ -90,7 +90,10 @@ def create_thermal_cluster(
args = {"thermal_name": thermal_name, **properties.model_dump(mode="json", exclude_none=True)}
local_thermal_properties = ThermalClusterPropertiesLocal.model_validate(args)

list_ini = IniFile(self.config.study_path, IniFileTypes.THERMAL_LIST_INI, area_id=area_id)
list_ini = IniFile(self.config.study_path, InitializationFilesTypes.THERMAL_LIST_INI, area_id=area_id)
IniFile(self.config.study_path, InitializationFilesTypes.THERMAL_PREPRO_MODULATION, area_id=area_id)
IniFile(self.config.study_path, InitializationFilesTypes.THERMAL_PREPRO_DATA, area_id=area_id)
IniFile(self.config.study_path, InitializationFilesTypes.THERMAL_SERIES, area_id=area_id)
try:
list_ini.add_section(local_thermal_properties.list_ini_fields)
except DuplicateSectionError:
Expand Down Expand Up @@ -129,7 +132,7 @@ def create_renewable_cluster(
args = {"renewable_name": renewable_name, **properties.model_dump(mode="json", exclude_none=True)}
local_properties = RenewableClusterPropertiesLocal.model_validate(args)

list_ini = IniFile(self.config.study_path, IniFileTypes.RENEWABLES_LIST_INI, area_id=area_id)
list_ini = IniFile(self.config.study_path, InitializationFilesTypes.RENEWABLES_LIST_INI, area_id=area_id)
list_ini.add_section(local_properties.ini_fields)
list_ini.write_ini_file()

Expand All @@ -152,7 +155,7 @@ def create_st_storage(
args = {"st_storage_name": st_storage_name, **properties.model_dump(mode="json", exclude_none=True)}
local_st_storage_properties = STStoragePropertiesLocal.model_validate(args)

list_ini = IniFile(self.config.study_path, IniFileTypes.ST_STORAGE_LIST_INI, area_id=area_id)
list_ini = IniFile(self.config.study_path, InitializationFilesTypes.ST_STORAGE_LIST_INI, area_id=area_id)
list_ini.add_section(local_st_storage_properties.list_ini_fields)
list_ini.write_ini_file(sort_sections=True)

Expand Down Expand Up @@ -187,10 +190,12 @@ def create_hydro(
args = {"area_id": area_id, **properties.model_dump(mode="json", exclude_none=True)}
local_hydro_properties = HydroPropertiesLocal.model_validate(args)

list_ini = IniFile(self.config.study_path, IniFileTypes.HYDRO_INI)
list_ini = IniFile(self.config.study_path, InitializationFilesTypes.HYDRO_INI)
list_ini.add_section(local_hydro_properties.hydro_ini_fields, append=True)
list_ini.write_ini_file(sort_section_content=True)

IniFile.create_hydro_initialization_files_for_area(self.config.study_path, area_id)

return Hydro(self, area_id, local_hydro_properties.yield_hydro_properties())

def read_hydro(
Expand Down Expand Up @@ -255,7 +260,7 @@ def _line_exists_in_file(file_content: str, line_to_add: str) -> bool:
# TODO: Handle districts in sets.ini later
sets_ini_content = _sets_ini_content()

with (self.config.study_path / IniFileTypes.AREAS_SETS_INI.value).open("w") as sets_ini:
with (self.config.study_path / InitializationFilesTypes.AREAS_SETS_INI.value).open("w") as sets_ini:
sets_ini_content.write(sets_ini)

local_properties = (
Expand All @@ -264,7 +269,9 @@ def _line_exists_in_file(file_content: str, line_to_add: str) -> bool:
else AreaPropertiesLocal()
)

adequacy_patch_ini = IniFile(self.config.study_path, IniFileTypes.AREA_ADEQUACY_PATCH_INI, area_name)
adequacy_patch_ini = IniFile(
self.config.study_path, InitializationFilesTypes.AREA_ADEQUACY_PATCH_INI, area_name
)
adequacy_patch_ini.add_section(local_properties.adequacy_patch())
adequacy_patch_ini.write_ini_file()

Expand All @@ -274,7 +281,7 @@ def _line_exists_in_file(file_content: str, line_to_add: str) -> bool:
with open(new_area_directory / "optimization.ini", "w") as optimization_ini_file:
optimization_ini.write(optimization_ini_file)

areas_ini = IniFile(self.config.study_path, IniFileTypes.THERMAL_AREAS_INI)
areas_ini = IniFile(self.config.study_path, InitializationFilesTypes.THERMAL_AREAS_INI)
if not areas_ini.ini_dict:
areas_ini.add_section({"unserverdenergycost": {}})
areas_ini.add_section({"spilledenergycost": {}})
Expand All @@ -290,6 +297,14 @@ def _line_exists_in_file(file_content: str, line_to_add: str) -> bool:
with open(new_area_directory / "ui.ini", "w") as ui_ini_file:
ui_ini.write(ui_ini_file)

empty_df = pd.DataFrame()
self.create_reserves(area_name, empty_df)
self.create_misc_gen(area_name, empty_df)
self.create_load(area_name, empty_df)
self.create_solar(area_name, empty_df)
self.create_wind(area_name, empty_df)
IniFile.create_link_ini_for_area(self.config.study_path, area_name)

except Exception as e:
raise AreaCreationError(area_name, f"{e}") from e

Expand Down Expand Up @@ -347,13 +362,15 @@ def read_areas(self) -> List[Area]:
for element in areas_path.iterdir():
if element.is_dir():
optimization_dict = IniFile(
self.config.study_path, IniFileTypes.AREA_OPTIMIZATION_INI, area_id=element.name
self.config.study_path, InitializationFilesTypes.AREA_OPTIMIZATION_INI, area_id=element.name
).ini_dict
area_adequacy_dict = IniFile(
self.config.study_path, IniFileTypes.AREA_ADEQUACY_PATCH_INI, area_id=element.name
self.config.study_path, InitializationFilesTypes.AREA_ADEQUACY_PATCH_INI, area_id=element.name
).ini_dict
ui_dict = IniFile(
self.config.study_path, InitializationFilesTypes.AREA_UI_INI, area_id=element.name
).ini_dict
ui_dict = IniFile(self.config.study_path, IniFileTypes.AREA_UI_INI, area_id=element.name).ini_dict
thermal_area_dict = IniFile(self.config.study_path, IniFileTypes.THERMAL_AREAS_INI).ini_dict
thermal_area_dict = IniFile(self.config.study_path, InitializationFilesTypes.THERMAL_AREAS_INI).ini_dict
area_properties = AreaPropertiesLocal(
non_dispatch_power=optimization_dict["nodal optimization"].get("non-dispatchable-power"),
dispatch_hydro_power=optimization_dict["nodal optimization"].get("dispatchable-hydro-power"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
DefaultBindingConstraintProperties,
)
from antares.craft.service.base_services import BaseBindingConstraintService
from antares.craft.tools.ini_tool import IniFile, IniFileTypes
from antares.craft.tools.ini_tool import IniFile, InitializationFilesTypes
from antares.craft.tools.matrix_tool import df_read, df_save
from antares.craft.tools.time_series_tool import TimeSeriesFileType
from pydantic import Field
Expand Down Expand Up @@ -77,7 +77,7 @@ def __init__(self, config: LocalConfiguration, study_name: str, **kwargs: Any) -
super().__init__(**kwargs)
self.config = config
self.study_name = study_name
self.ini_file = IniFile(self.config.study_path, IniFileTypes.BINDING_CONSTRAINTS_INI)
self.ini_file = IniFile(self.config.study_path, InitializationFilesTypes.BINDING_CONSTRAINTS_INI)

def create_binding_constraint(
self,
Expand Down
6 changes: 4 additions & 2 deletions src/antares/craft/service/local_services/link_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from antares.craft.service.base_services import BaseLinkService
from antares.craft.tools.contents_tool import sort_ini_sections
from antares.craft.tools.custom_raw_config_parser import CustomRawConfigParser
from antares.craft.tools.ini_tool import IniFile, IniFileTypes
from antares.craft.tools.ini_tool import IniFile, InitializationFilesTypes
from antares.craft.tools.matrix_tool import read_timeseries
from antares.craft.tools.time_series_tool import TimeSeriesFileType

Expand Down Expand Up @@ -175,7 +175,9 @@ def read_links(self) -> list[Link]:

for element in link_path.iterdir():
area_from = element.name
links_dict = IniFile(self.config.study_path, IniFileTypes.LINK_PROPERTIES_INI, area_id=area_from).ini_dict
links_dict = IniFile(
self.config.study_path, InitializationFilesTypes.LINK_PROPERTIES_INI, area_id=area_from
).ini_dict
# If the properties.ini doesn't exist, we stop the reading process
if links_dict:
for area_to in links_dict:
Expand Down
6 changes: 4 additions & 2 deletions src/antares/craft/service/local_services/renewable_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from antares.craft.config.local_configuration import LocalConfiguration
from antares.craft.model.renewable import RenewableCluster, RenewableClusterProperties, RenewableClusterPropertiesLocal
from antares.craft.service.base_services import BaseRenewableService
from antares.craft.tools.ini_tool import IniFile, IniFileTypes
from antares.craft.tools.ini_tool import IniFile, InitializationFilesTypes
from antares.craft.tools.matrix_tool import read_timeseries
from antares.craft.tools.time_series_tool import TimeSeriesFileType

Expand All @@ -40,7 +40,9 @@ def get_renewable_matrix(self, cluster_id: str, area_id: str) -> pd.DataFrame:
)

def read_renewables(self, area_id: str) -> List[RenewableCluster]:
renewable_dict = IniFile(self.config.study_path, IniFileTypes.RENEWABLES_LIST_INI, area_id=area_id).ini_dict
renewable_dict = IniFile(
self.config.study_path, InitializationFilesTypes.RENEWABLES_LIST_INI, area_id=area_id
).ini_dict
renewables_clusters = []
if renewable_dict:
for renewable_cluster in renewable_dict:
Expand Down
6 changes: 4 additions & 2 deletions src/antares/craft/service/local_services/thermal_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
ThermalClusterPropertiesLocal,
)
from antares.craft.service.base_services import BaseThermalService
from antares.craft.tools.ini_tool import IniFile, IniFileTypes
from antares.craft.tools.ini_tool import IniFile, InitializationFilesTypes
from antares.craft.tools.matrix_tool import read_timeseries
from antares.craft.tools.time_series_tool import TimeSeriesFileType

Expand Down Expand Up @@ -58,7 +58,9 @@ def get_thermal_matrix(self, thermal_cluster: ThermalCluster, ts_name: ThermalCl
)

def read_thermal_clusters(self, area_id: str) -> List[ThermalCluster]:
thermal_dict = IniFile(self.config.study_path, IniFileTypes.THERMAL_LIST_INI, area_id=area_id).ini_dict
thermal_dict = IniFile(
self.config.study_path, InitializationFilesTypes.THERMAL_LIST_INI, area_id=area_id
).ini_dict
thermal_clusters = []
if thermal_dict:
for thermal_cluster in thermal_dict:
Expand Down
55 changes: 52 additions & 3 deletions src/antares/craft/tools/ini_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@
from pydantic import BaseModel


class IniFileTypes(Enum):
class InitializationFilesTypes(Enum):
"""
The different ini files in an Antares project, files that are created for each area require using
The different initialization files (ini or txt) in an Antares project,
files that are created for each area require using
format(area_id=<name>) to get the complete path
"""

Expand All @@ -36,26 +37,42 @@ class IniFileTypes(Enum):
AREA_UI_INI = "input/areas/{area_id}/ui.ini"
AREA_ADEQUACY_PATCH_INI = "input/areas/{area_id}/adequacy_patch.ini"
BINDING_CONSTRAINTS_INI = "input/bindingconstraints/bindingconstraints.ini"

HYDRO_CORRELATION_INI = "input/hydro/prepro/correlation.ini"
HYDRO_INI = "input/hydro/hydro.ini"
HYDRO_CAPACITY_CM_TXT = "input/hydro/common/capacity/creditmodulations_{area_id}.txt"
HYDRO_CAPACITY_RE_TXT = "input/hydro/common/capacity/reservoir_{area_id}.txt"
HYDRO_CAPACITY_WV_TXT = "input/hydro/common/capacity/waterValues_{area_id}.txt"
HYDRO_CAPACITY_IP_TXT = "input/hydro/common/capacity/inflowPattern_{area_id}.txt"
HYDRO_SERIES_ROR_TXT = "input/hydro/series/{area_id}/ror.txt"
HYDRO_SERIES_MOD_TXT = "input/hydro/series/{area_id}/mod.txt"
HYDRO_SERIES_MIN_GEN_TXT = "input/hydro/series/{area_id}/mingen.txt"
HYDRO_COMMON_MAX_POWER = "input/hydro/common/capacity/maxpower_{area_id}.txt"

LINK_PROPERTIES_INI = "input/links/{area_id}/properties.ini"
LOAD_CORRELATION_INI = "input/load/prepro/correlation.ini"
LOAD_SETTINGS_INI = "input/load/prepro/{area_id}/settings.ini"
RENEWABLES_LIST_INI = "input/renewables/clusters/{area_id}/list.ini"
SOLAR_CORRELATION_INI = "input/solar/prepro/correlation.ini"
SOLAR_SETTINGS_INI = "input/solar/prepro/{area_id}/settings.ini"
ST_STORAGE_LIST_INI = "input/st-storage/clusters/{area_id}/list.ini"

THERMAL_AREAS_INI = "input/thermal/areas.ini"
THERMAL_LIST_INI = "input/thermal/clusters/{area_id}/list.ini"
THERMAL_PREPRO_MODULATION = "input/thermal/prepro/{area_id}/cluster/modulation.txt"
THERMAL_PREPRO_DATA = "input/thermal/prepro/{area_id}/cluster/data.txt"
THERMAL_SERIES = "input/thermal/series/{area_id}/cluster/series.txt"

WIND_CORRELATION_INI = "input/wind/prepro/correlation.ini"
WIND_SETTINGS_INI = "input/wind/prepro/{area_id}/settings.ini"
WIND_SERIES = "input/wind/series/wind_{area_id}.txt"


class IniFile:
def __init__(
self,
study_path: Path,
ini_file_type: IniFileTypes,
ini_file_type: InitializationFilesTypes,
area_id: Optional[str] = None,
ini_contents: Union[CustomRawConfigParser, dict[str, dict[str, str]], None] = None,
) -> None:
Expand Down Expand Up @@ -171,6 +188,38 @@ def _sort_ini_section_content(ini_to_sort: CustomRawConfigParser) -> CustomRawCo
sorted_ini[section] = {key: value for (key, value) in sorted(list(ini_to_sort[section].items()))}
return sorted_ini

@classmethod
def create_hydro_initialization_files_for_area(cls, study_path: Path, area_id: str) -> None:
"""
Creates IniFile instances for HYDRO_CAPACITY files
Args:
study_path (Path): The base path for the study.
area_id (str): The area ID.
Returns:
list[IniFile]: A list of IniFile instances for the capacity files.
"""
capacity_files = [
InitializationFilesTypes.HYDRO_CAPACITY_CM_TXT,
InitializationFilesTypes.HYDRO_CAPACITY_RE_TXT,
InitializationFilesTypes.HYDRO_CAPACITY_WV_TXT,
InitializationFilesTypes.HYDRO_CAPACITY_IP_TXT,
InitializationFilesTypes.HYDRO_SERIES_ROR_TXT,
InitializationFilesTypes.HYDRO_SERIES_MOD_TXT,
InitializationFilesTypes.HYDRO_SERIES_MIN_GEN_TXT,
InitializationFilesTypes.HYDRO_COMMON_MAX_POWER,
]

for file_type in capacity_files:
cls(study_path=study_path, ini_file_type=file_type, area_id=area_id)

@classmethod
def create_link_ini_for_area(cls, study_path: Path, area_id: str) -> None:
property_file = InitializationFilesTypes.LINK_PROPERTIES_INI

cls(study_path=study_path, ini_file_type=property_file, area_id=area_id)


def merge_dicts_for_ini(dict_a: dict[str, Any], dict_b: dict[str, Any]) -> dict:
"""
Expand Down
4 changes: 2 additions & 2 deletions src/antares/craft/tools/prepro_folder.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import numpy as np
import pandas as pd

from antares.craft.tools.ini_tool import IniFile, IniFileTypes
from antares.craft.tools.ini_tool import IniFile, InitializationFilesTypes
from antares.craft.tools.matrix_tool import df_save
from antares.craft.tools.time_series_tool import TimeSeriesFileType

Expand All @@ -26,7 +26,7 @@ class PreproFolder(Enum):
WIND = "wind"

def save(self, study_path: Path, area_id: str) -> None:
IniFile(study_path, IniFileTypes.__getitem__(f"{self.value.upper()}_SETTINGS_INI"), area_id)
IniFile(study_path, InitializationFilesTypes.__getitem__(f"{self.value.upper()}_SETTINGS_INI"), area_id)

conversion = TimeSeriesFileType.__getitem__(f"{self.value.upper()}_CONVERSION").value.format(area_id=area_id)
conversion_path = study_path.joinpath(conversion)
Expand Down
10 changes: 6 additions & 4 deletions tests/antares/integration/test_local_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from antares.craft.model.st_storage import STStorageGroup, STStorageProperties
from antares.craft.model.study import Study, create_study_local
from antares.craft.model.thermal import ThermalCluster, ThermalClusterGroup, ThermalClusterProperties
from antares.craft.tools.ini_tool import IniFile, IniFileTypes
from antares.craft.tools.ini_tool import IniFile, InitializationFilesTypes


class TestLocalClient:
Expand Down Expand Up @@ -118,7 +118,7 @@ def test_local_study(self, tmp_path, unknown_area):
assert area_be.ui.x == area_ui.x
assert area_be.ui.color_rgb == area_ui.color_rgb
be_ui_file = test_study.service.config.study_path.joinpath(
IniFileTypes.AREA_UI_INI.value.format(area_id=area_be.id)
InitializationFilesTypes.AREA_UI_INI.value.format(area_id=area_be.id)
)
assert be_ui_file.is_file()

Expand Down Expand Up @@ -148,10 +148,12 @@ def test_local_study(self, tmp_path, unknown_area):
assert link_be_fr.properties.hurdles_cost
assert link_be_fr.properties.filter_year_by_year == {FilterOption.HOURLY}
be_link_ini_file = test_study.service.config.study_path.joinpath(
IniFileTypes.LINK_PROPERTIES_INI.value.format(area_id=area_be.id)
InitializationFilesTypes.LINK_PROPERTIES_INI.value.format(area_id=area_be.id)
)
assert be_link_ini_file.is_file()
be_links_in_file = IniFile(test_study.service.config.study_path, IniFileTypes.LINK_PROPERTIES_INI, area_be.id)
be_links_in_file = IniFile(
test_study.service.config.study_path, InitializationFilesTypes.LINK_PROPERTIES_INI, area_be.id
)
assert be_links_in_file.ini_dict["fr"]["hurdles-cost"] == "true"
assert be_links_in_file.ini_dict["fr"]["filter-year-by-year"] == "hourly"

Expand Down
Loading

0 comments on commit 5f35882

Please sign in to comment.