Skip to content

Commit

Permalink
Merge pull request #2 from AntaresSimulatorTeam/feat/finish_solar_and…
Browse files Browse the repository at this point in the history
…_wind

feat/finish_solar_and_wind
  • Loading branch information
vargastat authored Sep 10, 2024
2 parents 6e77698 + 68bf243 commit 75e9870
Show file tree
Hide file tree
Showing 14 changed files with 883 additions and 42 deletions.
8 changes: 8 additions & 0 deletions src/antares/model/area.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

from antares.model.commons import FilterOption, sort_filter_values
from antares.model.hydro import HydroProperties, HydroMatrixName, Hydro
from antares.model.load import Load
from antares.model.misc_gen import MiscGen
from antares.model.renewable import RenewableCluster, RenewableClusterProperties
from antares.model.reserves import Reserves
Expand Down Expand Up @@ -242,6 +243,7 @@ def __init__( # type: ignore # TODO: Find a way to avoid circular imports
*,
renewables: Optional[Dict[str, RenewableCluster]] = None,
thermals: Optional[Dict[str, ThermalCluster]] = None,
load: Optional[Load] = None,
st_storages: Optional[Dict[str, STStorage]] = None,
hydro: Optional[Hydro] = None,
wind: Optional[Wind] = None,
Expand All @@ -259,6 +261,7 @@ def __init__( # type: ignore # TODO: Find a way to avoid circular imports
self._renewable_service = renewable_service
self._renewables = renewables or dict()
self._thermals = thermals or dict()
self._load = load
self._st_storages = st_storages or dict()
self._hydro = hydro
self._wind = wind
Expand Down Expand Up @@ -327,6 +330,11 @@ def create_renewable_cluster(
self._renewables[renewable.id] = renewable
return renewable

def create_load(self, series: Optional[pd.DataFrame]) -> Load:
load = self._area_service.create_load(self, series)
self._load = load
return load

def create_st_storage(self, st_storage_name: str, properties: Optional[STStorageProperties] = None) -> STStorage:
storage = self._area_service.create_st_storage(self.id, st_storage_name, properties)
self._st_storages[storage.id] = storage
Expand Down
40 changes: 40 additions & 0 deletions src/antares/model/load.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# 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 pathlib import Path
from typing import Optional

import pandas as pd

from antares.tools.prepro_folder import PreproFolder
from antares.tools.time_series_tool import TimeSeries, TimeSeriesFile


class Load:
def __init__(
self,
time_series: pd.DataFrame = pd.DataFrame([]),
local_file: Optional[TimeSeriesFile] = None,
study_path: Optional[Path] = None,
area_id: Optional[str] = None,
) -> None:
self._time_series = TimeSeries(time_series, local_file)
self._prepro = (
PreproFolder(folder="load", study_path=study_path, area_id=area_id) if study_path and area_id else None
)

@property
def time_series(self) -> TimeSeries:
return self._time_series

@property
def prepro(self) -> Optional[PreproFolder]:
return self._prepro
28 changes: 25 additions & 3 deletions src/antares/model/solar.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,32 @@
# SPDX-License-Identifier: MPL-2.0
#
# This file is part of the Antares project.
from pathlib import Path
from typing import Optional

import pandas as pd

from antares.tools.time_series_tool import TimeSeries
from antares.tools.prepro_folder import PreproFolder
from antares.tools.time_series_tool import TimeSeries, TimeSeriesFile


class Solar(TimeSeries):
pass
class Solar:
def __init__(
self,
time_series: pd.DataFrame = pd.DataFrame([]),
local_file: Optional[TimeSeriesFile] = None,
study_path: Optional[Path] = None,
area_id: Optional[str] = None,
) -> None:
self._time_series = TimeSeries(time_series, local_file)
self._prepro = (
PreproFolder(folder="solar", study_path=study_path, area_id=area_id) if study_path and area_id else None
)

@property
def time_series(self) -> TimeSeries:
return self._time_series

@property
def prepro(self) -> Optional[PreproFolder]:
return self._prepro
83 changes: 67 additions & 16 deletions src/antares/model/study.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import time
from pathlib import Path
from types import MappingProxyType
from typing import Optional, Dict, List
from typing import Optional, Dict, List, Any

import pandas as pd

Expand All @@ -30,6 +30,7 @@
from antares.service.api_services.study_api import _returns_study_settings
from antares.service.base_services import BaseStudyService
from antares.service.service_factory import ServiceFactory
from antares.tools.ini_tool import IniFile, IniFileTypes

"""
The study module defines the data model for antares study.
Expand Down Expand Up @@ -90,22 +91,55 @@ def create_study_local(
Raises:
FileExistsError if the study already exists in the given location
ValueError if the provided directory does not exist
"""

def _directory_not_exists(local_path: Path) -> None:
if local_path is None or not os.path.exists(local_path):
raise ValueError(f"Provided directory {local_path} does not exist.")

_directory_not_exists(local_config.local_path)
def _create_directory_structure(study_path: Path) -> None:
subdirectories = [
"input/hydro/allocation",
"input/hydro/common/capacity",
"input/hydro/series",
"input/links",
"input/load/series",
"input/misc-gen",
"input/reserves",
"input/solar/series",
"input/thermal/clusters",
"input/thermal/prepro",
"input/thermal/series",
"input/wind/series",
"layers",
"output",
"settings/resources",
"settings/simulations",
"user",
]
for subdirectory in subdirectories:
(study_path / subdirectory).mkdir(parents=True, exist_ok=True)

def _correlation_defaults() -> dict[str, dict[str, str]]:
return {
"general": {"mode": "annual"},
"annual": {},
"0": {},
"1": {},
"2": {},
"3": {},
"4": {},
"5": {},
"6": {},
"7": {},
"8": {},
"9": {},
"10": {},
"11": {},
}

study_directory = local_config.local_path / study_name

_verify_study_already_exists(study_directory)

# Create the main study directory
os.makedirs(study_directory, exist_ok=True)
# Create the directory structure
_create_directory_structure(study_directory)

# Create study.antares file with timestamps and study_name
antares_file_path = os.path.join(study_directory, "study.antares")
Expand All @@ -130,24 +164,38 @@ def _directory_not_exists(local_path: Path) -> None:
with open(desktop_ini_path, "w") as desktop_ini_file:
desktop_ini_file.write(desktop_ini_content)

# Create subdirectories
subdirectories = ["input", "layers", "output", "setting", "user"]
for subdirectory in subdirectories:
subdirectory_path = os.path.join(study_directory, subdirectory)
os.makedirs(subdirectory_path, exist_ok=True)
# Create various .ini files for the study
correlation_inis_to_create = [
("solar_correlation", IniFileTypes.SOLAR_CORRELATION_INI),
("wind_correlation", IniFileTypes.WIND_CORRELATION_INI),
("load_correlation", IniFileTypes.LOAD_CORRELATION_INI),
]
ini_files = {
correlation: IniFile(study_directory, file_type, ini_contents=_correlation_defaults())
for (correlation, file_type) in correlation_inis_to_create
}
for ini_file in ini_files.keys():
ini_files[ini_file].write_ini_file()

logging.info(f"Study successfully created: {study_name}")
return Study(
name=study_name,
version=version,
service_factory=ServiceFactory(config=local_config, study_name=study_name),
settings=settings,
ini_files=ini_files,
)


class Study:
def __init__(
self, name: str, version: str, service_factory: ServiceFactory, settings: Optional[StudySettings] = None
self,
name: str,
version: str,
service_factory: ServiceFactory,
settings: Optional[StudySettings] = None,
# ini_files: Optional[dict[str, IniFile]] = None,
**kwargs: Any,
):
self.name = name
self.version = version
Expand All @@ -159,6 +207,9 @@ def __init__(
self._areas: Dict[str, Area] = dict()
self._links: Dict[str, Link] = dict()
self._binding_constraints: Dict[str, BindingConstraint] = dict()
for argument in kwargs:
if argument == "ini_files":
self._ini_files: dict[str, IniFile] = kwargs[argument] or dict()

@property
def service(self) -> BaseStudyService:
Expand Down
28 changes: 25 additions & 3 deletions src/antares/model/wind.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,32 @@
# SPDX-License-Identifier: MPL-2.0
#
# This file is part of the Antares project.
from pathlib import Path
from typing import Optional

import pandas as pd

from antares.tools.time_series_tool import TimeSeries
from antares.tools.prepro_folder import PreproFolder
from antares.tools.time_series_tool import TimeSeries, TimeSeriesFile


class Wind(TimeSeries):
pass
class Wind:
def __init__(
self,
time_series: pd.DataFrame = pd.DataFrame([]),
local_file: Optional[TimeSeriesFile] = None,
study_path: Optional[Path] = None,
area_id: Optional[str] = None,
) -> None:
self._time_series = TimeSeries(time_series, local_file)
self._prepro = (
PreproFolder(folder="wind", study_path=study_path, area_id=area_id) if study_path and area_id else None
)

@property
def time_series(self) -> TimeSeries:
return self._time_series

@property
def prepro(self) -> Optional[PreproFolder]:
return self._prepro
8 changes: 6 additions & 2 deletions src/antares/service/api_services/area_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
)
from antares.model.area import AreaProperties, AreaUi, Area
from antares.model.hydro import HydroProperties, HydroMatrixName, Hydro
from antares.model.load import Load
from antares.model.misc_gen import MiscGen
from antares.model.renewable import RenewableClusterProperties, RenewableCluster
from antares.model.reserves import Reserves
Expand Down Expand Up @@ -323,6 +324,9 @@ def create_renewable_cluster(

return RenewableCluster(self.renewable_service, area_id, name, properties)

def create_load(self, area: Area, series: Optional[pd.DataFrame]) -> Load:
raise NotImplementedError

def create_st_storage(
self, area_id: str, st_storage_name: str, properties: Optional[STStorageProperties] = None
) -> STStorage:
Expand Down Expand Up @@ -370,7 +374,7 @@ def create_wind(self, area: Area, series: Optional[pd.DataFrame]) -> Wind:
series = series if series is not None else pd.DataFrame([])
series_path = f"input/wind/series/wind_{area.id}"
self._upload_series(area, series, series_path)
return Wind(series)
return Wind(time_series=series)

def create_reserves(self, area: Area, series: Optional[pd.DataFrame]) -> Reserves:
series = series if series is not None else pd.DataFrame([])
Expand All @@ -382,7 +386,7 @@ def create_solar(self, area: Area, series: Optional[pd.DataFrame]) -> Solar:
series = series if series is not None else pd.DataFrame([])
series_path = f"input/solar/series/solar_{area.id}"
self._upload_series(area, series, series_path)
return Solar(series)
return Solar(time_series=series)

def create_misc_gen(self, area: Area, series: Optional[pd.DataFrame]) -> MiscGen:
series = series if series is not None else pd.DataFrame([])
Expand Down
11 changes: 11 additions & 0 deletions src/antares/service/base_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
)
from antares.model.hydro import HydroProperties, HydroMatrixName, Hydro
from antares.model.link import LinkProperties, LinkUi, Link
from antares.model.load import Load
from antares.model.misc_gen import MiscGen
from antares.model.renewable import RenewableClusterProperties, RenewableCluster
from antares.model.reserves import Reserves
Expand Down Expand Up @@ -120,6 +121,16 @@ def create_renewable_cluster(
"""
pass

@abstractmethod
def create_load(self, area: Area, series: Optional[pd.DataFrame]) -> Load:
"""
Args:
area: area to create load series matrices
series: load/series/load_{area_id}.txt
"""
pass

@abstractmethod
def create_st_storage(
self, area_id: str, st_storage_name: str, properties: Optional[STStorageProperties] = None
Expand Down
10 changes: 8 additions & 2 deletions src/antares/service/local_services/area_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from antares.exceptions.exceptions import CustomError
from antares.model.area import AreaProperties, AreaUi, Area, AreaPropertiesLocal, AreaUiLocal
from antares.model.hydro import HydroProperties, HydroMatrixName, Hydro, HydroPropertiesLocal
from antares.model.load import Load
from antares.model.misc_gen import MiscGen
from antares.model.renewable import RenewableClusterProperties, RenewableCluster, RenewableClusterPropertiesLocal
from antares.model.reserves import Reserves
Expand Down Expand Up @@ -116,6 +117,11 @@ def create_renewable_cluster(
self.renewable_service, area_id, renewable_name, local_properties.yield_renewable_cluster_properties()
)

def create_load(self, area: Area, series: Optional[pd.DataFrame]) -> Load:
series = series if series is not None else pd.DataFrame([])
local_file = TimeSeriesFile(TimeSeriesFileType.LOAD, self.config.study_path, area.id, series)
return Load(time_series=series, local_file=local_file, study_path=self.config.study_path, area_id=area.id)

def create_st_storage(
self, area_id: str, st_storage_name: str, properties: Optional[STStorageProperties] = None
) -> STStorage:
Expand All @@ -135,7 +141,7 @@ def create_st_storage(
def create_wind(self, area: Area, series: Optional[pd.DataFrame]) -> Wind:
series = series if series is not None else pd.DataFrame([])
local_file = TimeSeriesFile(TimeSeriesFileType.WIND, self.config.study_path, area.id, series)
return Wind(series, local_file)
return Wind(time_series=series, local_file=local_file, study_path=self.config.study_path, area_id=area.id)

def create_reserves(self, area: Area, series: Optional[pd.DataFrame]) -> Reserves:
series = series if series is not None else pd.DataFrame([])
Expand All @@ -145,7 +151,7 @@ def create_reserves(self, area: Area, series: Optional[pd.DataFrame]) -> Reserve
def create_solar(self, area: Area, series: Optional[pd.DataFrame]) -> Solar:
series = series if series is not None else pd.DataFrame([])
local_file = TimeSeriesFile(TimeSeriesFileType.SOLAR, self.config.study_path, area.id, series)
return Solar(series, local_file)
return Solar(time_series=series, local_file=local_file, study_path=self.config.study_path, area_id=area.id)

def create_misc_gen(self, area: Area, series: Optional[pd.DataFrame]) -> MiscGen:
series = series if series is not None else pd.DataFrame([])
Expand Down
Loading

0 comments on commit 75e9870

Please sign in to comment.