Skip to content

Commit

Permalink
refactor(thermal, renewable): create user classes (#79)
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinBelthle authored Feb 12, 2025
1 parent a26e9f0 commit a5d6a44
Show file tree
Hide file tree
Showing 27 changed files with 694 additions and 543 deletions.
25 changes: 9 additions & 16 deletions src/antares/craft/model/area.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,24 +256,17 @@ def ui(self) -> AreaUi:
return self._ui

def create_thermal_cluster(
self, thermal_name: str, properties: Optional[ThermalClusterProperties] = None
) -> ThermalCluster:
thermal = self._area_service.create_thermal_cluster(self.id, thermal_name, properties)
self._thermals[thermal.id] = thermal
return thermal

def create_thermal_cluster_with_matrices(
self,
cluster_name: str,
parameters: ThermalClusterProperties,
prepro: Optional[pd.DataFrame],
modulation: Optional[pd.DataFrame],
series: Optional[pd.DataFrame],
CO2Cost: Optional[pd.DataFrame],
fuelCost: Optional[pd.DataFrame],
thermal_name: str,
properties: Optional[ThermalClusterProperties] = None,
prepro: Optional[pd.DataFrame] = None,
modulation: Optional[pd.DataFrame] = None,
series: Optional[pd.DataFrame] = None,
co2_cost: Optional[pd.DataFrame] = None,
fuel_cost: Optional[pd.DataFrame] = None,
) -> ThermalCluster:
thermal = self._area_service.create_thermal_cluster_with_matrices(
self.id, cluster_name, parameters, prepro, modulation, series, CO2Cost, fuelCost
thermal = self._area_service.create_thermal_cluster(
self.id, thermal_name, properties, prepro, modulation, series, co2_cost, fuel_cost
)
self._thermals[thermal.id] = thermal
return thermal
Expand Down
27 changes: 12 additions & 15 deletions src/antares/craft/model/cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,34 +9,31 @@
# SPDX-License-Identifier: MPL-2.0
#
# This file is part of the Antares project.

from dataclasses import dataclass
from typing import Optional

from pydantic import BaseModel
from pydantic.alias_generators import to_camel


class ClusterProperties(BaseModel, extra="forbid", populate_by_name=True, alias_generator=to_camel):
@dataclass
class ClusterProperties:
"""
Common properties for thermal and renewable clusters
"""

# Activity status:
# - True: the plant may generate.
# - False: not yet commissioned, moth-balled, etc.
enabled: bool = True

unit_count: int = 1
nominal_capacity: float = 0

@property
def installed_capacity(self) -> Optional[float]:
if self.unit_count is None or self.nominal_capacity is None:
return None
def installed_capacity(self) -> float:
return self.unit_count * self.nominal_capacity

@property
def enabled_capacity(self) -> Optional[float]:
if self.enabled is None or self.installed_capacity is None:
return None
def enabled_capacity(self) -> float:
return self.enabled * self.installed_capacity


@dataclass
class ClusterPropertiesUpdate:
enabled: Optional[bool] = None
unit_count: Optional[int] = None
nominal_capacity: Optional[float] = None
42 changes: 9 additions & 33 deletions src/antares/craft/model/renewable.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,14 @@
# 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.model.cluster import ClusterProperties
from antares.craft.model.cluster import ClusterProperties, ClusterPropertiesUpdate
from antares.craft.service.base_services import BaseRenewableService
from antares.craft.tools.all_optional_meta import all_optional_model
from antares.craft.tools.contents_tool import transform_name_to_id


Expand Down Expand Up @@ -55,39 +54,16 @@ class TimeSeriesInterpretation(Enum):
PRODUCTION_FACTOR = "production-factor"


class DefaultRenewableClusterProperties(ClusterProperties):
"""
Properties of a renewable cluster read from the configuration files.
"""

@dataclass
class RenewableClusterProperties(ClusterProperties):
group: RenewableClusterGroup = RenewableClusterGroup.OTHER1
ts_interpretation: TimeSeriesInterpretation = TimeSeriesInterpretation.POWER_GENERATION


@all_optional_model
class RenewableClusterProperties(DefaultRenewableClusterProperties):
pass


class RenewableClusterPropertiesLocal(DefaultRenewableClusterProperties):
renewable_name: str

@property
def ini_fields(self) -> dict[str, dict[str, str]]:
return {
self.renewable_name: {
"name": self.renewable_name,
"group": self.group.value,
"enabled": f"{self.enabled}".lower(),
"nominalcapacity": f"{self.nominal_capacity:.6f}",
"unitcount": f"{self.unit_count}",
"ts-interpretation": self.ts_interpretation.value,
}
}

def yield_renewable_cluster_properties(self) -> RenewableClusterProperties:
excludes = {"renewable_name", "ini_fields"}
return RenewableClusterProperties.model_validate(self.model_dump(mode="json", exclude=excludes))
@dataclass
class RenewableClusterPropertiesUpdate(ClusterPropertiesUpdate):
group: Optional[RenewableClusterGroup] = None
ts_interpretation: Optional[TimeSeriesInterpretation] = None


class RenewableCluster:
Expand Down Expand Up @@ -122,7 +98,7 @@ def id(self) -> str:
def properties(self) -> RenewableClusterProperties:
return self._properties

def update_properties(self, properties: RenewableClusterProperties) -> None:
def update_properties(self, properties: RenewableClusterPropertiesUpdate) -> None:
new_properties = self._renewable_service.update_renewable_properties(self, properties)
self._properties = new_properties

Expand Down
105 changes: 39 additions & 66 deletions src/antares/craft/model/thermal.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,14 @@
# 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.model.cluster import ClusterProperties
from antares.craft.model.cluster import ClusterProperties, ClusterPropertiesUpdate
from antares.craft.service.base_services import BaseThermalService
from antares.craft.tools.all_optional_meta import all_optional_model
from antares.craft.tools.contents_tool import transform_name_to_id


Expand Down Expand Up @@ -65,12 +64,8 @@ class ThermalCostGeneration(Enum):
USE_COST_TIME_SERIES = "useCostTimeseries"


class DefaultThermalProperties(ClusterProperties):
"""
Thermal cluster configuration model.
This model describes the configuration parameters for a thermal cluster.
"""

@dataclass
class ThermalClusterProperties(ClusterProperties):
group: ThermalClusterGroup = ThermalClusterGroup.OTHER1
gen_ts: LocalTSGenerationBehavior = LocalTSGenerationBehavior.USE_GLOBAL
min_stable_power: float = 0
Expand All @@ -88,7 +83,6 @@ class DefaultThermalProperties(ClusterProperties):
startup_cost: float = 0
market_bid_cost: float = 0
co2: float = 0
# version 860
nh3: float = 0
so2: float = 0
nox: float = 0
Expand All @@ -101,66 +95,45 @@ class DefaultThermalProperties(ClusterProperties):
op3: float = 0
op4: float = 0
op5: float = 0
# version 870
cost_generation: ThermalCostGeneration = ThermalCostGeneration.SET_MANUALLY
efficiency: float = 100
variable_o_m_cost: float = 0


@all_optional_model
class ThermalClusterProperties(DefaultThermalProperties):
pass


class ThermalClusterPropertiesLocal(DefaultThermalProperties):
thermal_name: str

@property
def list_ini_fields(self) -> dict[str, dict[str, str]]:
return {
f"{self.thermal_name}": {
"group": self.group.value,
"name": self.thermal_name,
"enabled": f"{self.enabled}",
"unitcount": f"{self.unit_count}",
"nominalcapacity": f"{self.nominal_capacity:.6f}",
"gen-ts": self.gen_ts.value,
"min-stable-power": f"{self.min_stable_power:.6f}",
"min-up-time": f"{self.min_up_time}",
"min-down-time": f"{self.min_down_time}",
"must-run": f"{self.must_run}",
"spinning": f"{self.spinning:.6f}",
"volatility.forced": f"{self.volatility_forced:.6f}",
"volatility.planned": f"{self.volatility_planned:.6f}",
"law.forced": self.law_forced.value,
"law.planned": self.law_planned.value,
"marginal-cost": f"{self.marginal_cost:.6f}",
"spread-cost": f"{self.spread_cost:.6f}",
"fixed-cost": f"{self.fixed_cost:.6f}",
"startup-cost": f"{self.startup_cost:.6f}",
"market-bid-cost": f"{self.market_bid_cost:.6f}",
"co2": f"{self.co2:.6f}",
"nh3": f"{self.nh3:.6f}",
"so2": f"{self.so2:.6f}",
"nox": f"{self.nox:.6f}",
"pm2_5": f"{self.pm2_5:.6f}",
"pm5": f"{self.pm5:.6f}",
"pm10": f"{self.pm10:.6f}",
"nmvoc": f"{self.nmvoc:.6f}",
"op1": f"{self.op1:.6f}",
"op2": f"{self.op2:.6f}",
"op3": f"{self.op3:.6f}",
"op4": f"{self.op4:.6f}",
"op5": f"{self.op5:.6f}",
"costgeneration": self.cost_generation.value,
"efficiency": f"{self.efficiency:.6f}",
"variableomcost": f"{self.variable_o_m_cost:.6f}",
}
}

def yield_thermal_cluster_properties(self) -> ThermalClusterProperties:
excludes = {"thermal_name", "list_ini_fields"}
return ThermalClusterProperties.model_validate(self.model_dump(mode="json", exclude=excludes))
@dataclass
class ThermalClusterPropertiesUpdate(ClusterPropertiesUpdate):
group: Optional[ThermalClusterGroup] = None
gen_ts: Optional[LocalTSGenerationBehavior] = None
min_stable_power: Optional[float] = None
min_up_time: Optional[int] = None
min_down_time: Optional[int] = None
must_run: Optional[bool] = None
spinning: Optional[float] = None
volatility_forced: Optional[float] = None
volatility_planned: Optional[float] = None
law_forced: Optional[LawOption] = None
law_planned: Optional[LawOption] = None
marginal_cost: Optional[float] = None
spread_cost: Optional[float] = None
fixed_cost: Optional[float] = None
startup_cost: Optional[float] = None
market_bid_cost: Optional[float] = None
co2: Optional[float] = None
nh3: Optional[float] = None
so2: Optional[float] = None
nox: Optional[float] = None
pm2_5: Optional[float] = None
pm5: Optional[float] = None
pm10: Optional[float] = None
nmvoc: Optional[float] = None
op1: Optional[float] = None
op2: Optional[float] = None
op3: Optional[float] = None
op4: Optional[float] = None
op5: Optional[float] = None
cost_generation: Optional[ThermalCostGeneration] = None
efficiency: Optional[float] = None
variable_o_m_cost: Optional[float] = None


class ThermalClusterMatrixName(Enum):
Expand Down Expand Up @@ -203,7 +176,7 @@ def id(self) -> str:
def properties(self) -> ThermalClusterProperties:
return self._properties

def update_properties(self, properties: ThermalClusterProperties) -> None:
def update_properties(self, properties: ThermalClusterPropertiesUpdate) -> None:
new_properties = self._thermal_service.update_thermal_properties(self, properties)
self._properties = new_properties

Expand Down
Loading

0 comments on commit a5d6a44

Please sign in to comment.