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(settings): refactor settings to create an user oriented class #73

Open
wants to merge 69 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
8830197
start work
MartinBelthle Jan 30, 2025
cb5f310
remove ts inside settings
MartinBelthle Jan 30, 2025
5a51bd4
continue work
MartinBelthle Jan 30, 2025
2b41478
fix typo
MartinBelthle Jan 30, 2025
48a1971
continue
MartinBelthle Jan 30, 2025
972f07a
continue work
MartinBelthle Jan 30, 2025
6d1f0e8
add all new classes
MartinBelthle Jan 30, 2025
8493952
move api related classes
MartinBelthle Jan 30, 2025
b30e77a
move local classes
MartinBelthle Jan 30, 2025
6b98c00
remove useless file
MartinBelthle Jan 30, 2025
f22c4f7
create first method
MartinBelthle Jan 30, 2025
0f4dd5c
make one test ok
MartinBelthle Jan 30, 2025
23ebfa1
continue work for API
MartinBelthle Jan 30, 2025
658062c
continue work
MartinBelthle Jan 30, 2025
a5383c8
continue work for API
MartinBelthle Jan 30, 2025
9f254cb
continue work api
MartinBelthle Jan 30, 2025
2b4657a
continue
MartinBelthle Jan 31, 2025
e339f8e
add all methods inside API classes
MartinBelthle Jan 31, 2025
1942f95
add minor thing
MartinBelthle Jan 31, 2025
501e6d9
add method read_study_settings
MartinBelthle Jan 31, 2025
8db9cef
rename method
MartinBelthle Jan 31, 2025
441fd44
create function edit_study_settings
MartinBelthle Jan 31, 2025
26109f4
refactoring
MartinBelthle Jan 31, 2025
bf4746f
remove legacy function
MartinBelthle Jan 31, 2025
2155c94
make function private
MartinBelthle Jan 31, 2025
3e18e33
remove try catch
MartinBelthle Jan 31, 2025
06f0af7
fix duplicata
MartinBelthle Jan 31, 2025
e956074
handle playlist
MartinBelthle Jan 31, 2025
7a8e216
use playlist
MartinBelthle Jan 31, 2025
9e4da02
add todo
MartinBelthle Jan 31, 2025
04663bb
start work for local models
MartinBelthle Jan 31, 2025
be62d63
add mc scenario
MartinBelthle Jan 31, 2025
b2ea01b
continue work
MartinBelthle Jan 31, 2025
939d4ff
continue work
MartinBelthle Jan 31, 2025
42a9afa
use inheritance
MartinBelthle Jan 31, 2025
5929fe0
put back method
MartinBelthle Jan 31, 2025
5be9698
refactor exisiting function
MartinBelthle Jan 31, 2025
882231f
create 2 new methods
MartinBelthle Jan 31, 2025
c9a3449
move API methods
MartinBelthle Jan 31, 2025
7467574
use general data path
MartinBelthle Jan 31, 2025
c22f8a8
start coding
MartinBelthle Jan 31, 2025
0e72ef7
continue work
MartinBelthle Jan 31, 2025
fd6cb90
do the first lines of thematic and playlist
MartinBelthle Jan 31, 2025
4a8d845
remove edition class
MartinBelthle Feb 3, 2025
736306d
finalize function
MartinBelthle Feb 3, 2025
790e33b
add the writing
MartinBelthle Feb 3, 2025
30ba1e9
use read and edit
MartinBelthle Feb 3, 2025
f365333
remove stupid test
MartinBelthle Feb 3, 2025
1fa808a
remove useless functions
MartinBelthle Feb 3, 2025
cce8bc8
fix lots of tests
MartinBelthle Feb 3, 2025
7e84e80
finalize tests
MartinBelthle Feb 3, 2025
a0627b3
fix tets
MartinBelthle Feb 3, 2025
611fce9
fix test
MartinBelthle Feb 3, 2025
b9843e4
start rewriting test
MartinBelthle Feb 3, 2025
45b3d6b
return the right settings inside edit settings
MartinBelthle Feb 3, 2025
2ba1c37
fix default value
MartinBelthle Feb 3, 2025
cb78148
start re writing test
MartinBelthle Feb 3, 2025
575d6a4
fix correlation code
MartinBelthle Feb 3, 2025
35176a8
fix code
MartinBelthle Feb 3, 2025
6cffccd
fix one tets
MartinBelthle Feb 3, 2025
9abb538
fix code
MartinBelthle Feb 4, 2025
d0e30e2
fix test
MartinBelthle Feb 4, 2025
2d1c7c5
put back old values
MartinBelthle Feb 4, 2025
1d3056a
put back old values
MartinBelthle Feb 4, 2025
820428e
remove temporarily playlist and thematic trimming tests
MartinBelthle Feb 4, 2025
940f29e
fix integration test
MartinBelthle Feb 4, 2025
45157ae
fix tests
MartinBelthle Feb 4, 2025
f01eac3
merge with main
MartinBelthle Feb 5, 2025
aadadde
fix tets
MartinBelthle Feb 5, 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
6 changes: 6 additions & 0 deletions src/antares/craft/exceptions/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,12 @@ def __init__(self, study_name: str, message: str) -> None:
super().__init__(self.message)


class StudySettingsReadError(Exception):
def __init__(self, study_name: str, message: str) -> None:
self.message = f"Could not read settings for study {study_name}: " + message
super().__init__(self.message)


class StudyDeletionError(Exception):
def __init__(self, study_id: str, message: str) -> None:
self.message = f"Could not delete the study {study_id}: " + message
Expand Down
61 changes: 13 additions & 48 deletions src/antares/craft/model/settings/adequacy_patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,59 +9,24 @@
# SPDX-License-Identifier: MPL-2.0
#
# This file is part of the Antares project.

from dataclasses import dataclass
from enum import Enum

from antares.craft.tools.all_optional_meta import all_optional_model
from pydantic import BaseModel, ConfigDict, Field
from pydantic.alias_generators import to_camel
from typing import Optional


class PriceTakingOrder(Enum):
DENS = "DENS"
LOAD = "Load"


class DefaultAdequacyPatchParameters(BaseModel, populate_by_name=True, alias_generator=to_camel):
model_config = ConfigDict(use_enum_values=True)

# version 830
enable_adequacy_patch: bool = False
ntc_from_physical_areas_out_to_physical_areas_in_adequacy_patch: bool = True
ntc_between_physical_areas_out_adequacy_patch: bool = True
# version 850
price_taking_order: PriceTakingOrder = Field(default=PriceTakingOrder.DENS, validate_default=True)
include_hurdle_cost_csr: bool = False
check_csr_cost_function: bool = False
enable_first_step: bool = False
threshold_initiate_curtailment_sharing_rule: int = 0
threshold_display_local_matching_rule_violations: int = 0
threshold_csr_variable_bounds_relaxation: int = 3


@all_optional_model
class AdequacyPatchParameters(DefaultAdequacyPatchParameters):
pass


class AdequacyPatchParametersLocal(DefaultAdequacyPatchParameters):
@property
def ini_fields(self) -> dict:
return {
"adequacy patch": {
"include-adq-patch": str(self.enable_adequacy_patch).lower(),
"set-to-null-ntc-from-physical-out-to-physical-in-for-first-step": str(
self.ntc_from_physical_areas_out_to_physical_areas_in_adequacy_patch
).lower(),
"set-to-null-ntc-between-physical-out-for-first-step": str(
self.ntc_between_physical_areas_out_adequacy_patch
).lower(),
"enable-first-step": str(self.enable_first_step).lower(),
"price-taking-order": self.price_taking_order,
"include-hurdle-cost-csr": str(self.include_hurdle_cost_csr).lower(),
"check-csr-cost-function": str(self.check_csr_cost_function).lower(),
"threshold-initiate-curtailment-sharing-rule": f"{self.threshold_initiate_curtailment_sharing_rule:.6f}",
"threshold-display-local-matching-rule-violations": f"{self.threshold_display_local_matching_rule_violations:.6f}",
"threshold-csr-variable-bounds-relaxation": f"{self.threshold_csr_variable_bounds_relaxation}",
}
}
@dataclass
class AdequacyPatchParameters:
include_adq_patch: Optional[bool] = None
set_to_null_ntc_from_physical_out_to_physical_in_for_first_step: Optional[bool] = None
set_to_null_ntc_between_physical_out_for_first_step: Optional[bool] = None
price_taking_order: Optional[PriceTakingOrder] = None
include_hurdle_cost_csr: Optional[bool] = None
check_csr_cost_function: Optional[bool] = None
threshold_initiate_curtailment_sharing_rule: Optional[int] = None
threshold_display_local_matching_rule_violations: Optional[int] = None
threshold_csr_variable_bounds_relaxation: Optional[int] = None
111 changes: 23 additions & 88 deletions src/antares/craft/model/settings/advanced_parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,11 @@
# 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 Any, Optional
from typing import Optional

from antares.craft.model.settings.general import OutputChoices
from antares.craft.tools.alias_generators import to_kebab
from antares.craft.tools.all_optional_meta import all_optional_model
from pydantic import BaseModel, ConfigDict, Field, model_validator
from pydantic.alias_generators import to_camel
from typing_extensions import Self


class InitialReservoirLevel(Enum):
Expand Down Expand Up @@ -47,10 +42,6 @@ class SheddingPolicy(Enum):
MINIMIZE_DURATION = "minimize duration"


class ReserveManagement(Enum):
GLOBAL = "global"


class UnitCommitmentMode(Enum):
FAST = "fast"
ACCURATE = "accurate"
Expand All @@ -70,81 +61,25 @@ class RenewableGenerationModeling(Enum):
CLUSTERS = "clusters"


class DefaultAdvancedParameters(BaseModel, alias_generator=to_camel):
model_config = ConfigDict(use_enum_values=True)

# Advanced parameters
@dataclass
class AdvancedParameters:
initial_reservoir_levels: Optional[InitialReservoirLevel] = None
hydro_heuristic_policy: Optional[HydroHeuristicPolicy] = None
hydro_pricing_mode: Optional[HydroPricingMode] = None
power_fluctuations: Optional[PowerFluctuation] = None
shedding_policy: Optional[SheddingPolicy] = None
unit_commitment_mode: Optional[UnitCommitmentMode] = None
number_of_cores_mode: Optional[SimulationCore] = None
renewable_generation_modelling: Optional[RenewableGenerationModeling] = None
accuracy_on_correlation: Optional[set[OutputChoices]] = None
# Other preferences
initial_reservoir_levels: InitialReservoirLevel = Field(
default=InitialReservoirLevel.COLD_START, validate_default=True
)
hydro_heuristic_policy: HydroHeuristicPolicy = Field(
default=HydroHeuristicPolicy.ACCOMMODATE_RULES_CURVES, validate_default=True
)
hydro_pricing_mode: HydroPricingMode = Field(default=HydroPricingMode.FAST, validate_default=True)
power_fluctuations: PowerFluctuation = Field(default=PowerFluctuation.FREE_MODULATIONS, validate_default=True)
shedding_policy: SheddingPolicy = Field(default=SheddingPolicy.SHAVE_PEAKS, validate_default=True)
unit_commitment_mode: UnitCommitmentMode = Field(default=UnitCommitmentMode.FAST, validate_default=True)
number_of_cores_mode: SimulationCore = Field(default=SimulationCore.MEDIUM, validate_default=True)
renewable_generation_modelling: RenewableGenerationModeling = Field(
default=RenewableGenerationModeling.AGGREGATED, validate_default=True
)
# Seeds
seed_tsgen_wind: int = 5489
seed_tsgen_load: int = 1005489
seed_tsgen_hydro: int = 2005489
seed_tsgen_thermal: int = 3005489
seed_tsgen_solar: int = 4005489
seed_tsnumbers: int = 5005489
seed_unsupplied_energy_costs: int = 6005489
seed_spilled_energy_costs: int = 7005489
seed_thermal_costs: int = 8005489
seed_hydro_costs: int = 9005489
seed_initial_reservoir_levels: int = 10005489


@all_optional_model
class AdvancedParameters(DefaultAdvancedParameters):
@model_validator(mode="before")
def change_accuracy_on_correlation(cls, data: Any) -> Self:
if "accuracyOnCorrelation" in data.keys():
data["accuracyOnCorrelation"] = (
{OutputChoices(list_item) for list_item in data["accuracyOnCorrelation"].replace(" ", "").split(",")}
if data["accuracyOnCorrelation"]
else None
)
return data


class AdvancedParametersLocal(DefaultAdvancedParameters, alias_generator=to_kebab):
@property
def ini_fields(self) -> dict:
return {
"other preferences": {
"initial-reservoir-levels": self.initial_reservoir_levels,
"hydro-heuristic-policy": self.hydro_heuristic_policy,
"hydro-pricing-mode": self.hydro_pricing_mode,
"power-fluctuations": self.power_fluctuations,
"shedding-policy": self.shedding_policy,
"unit-commitment-mode": self.unit_commitment_mode,
"number-of-cores-mode": self.number_of_cores_mode,
"renewable-generation-modelling": self.renewable_generation_modelling,
},
"advanced parameters": {
"accuracy-on-correlation": self.accuracy_on_correlation if self.accuracy_on_correlation else "",
},
"seeds - Mersenne Twister": {
"seed-tsgen-wind": str(self.seed_tsgen_wind),
"seed-tsgen-load": str(self.seed_tsgen_load),
"seed-tsgen-hydro": str(self.seed_tsgen_hydro),
"seed-tsgen-thermal": str(self.seed_tsgen_thermal),
"seed-tsgen-solar": str(self.seed_tsgen_solar),
"seed-tsnumbers": str(self.seed_tsnumbers),
"seed-unsupplied-energy-costs": str(self.seed_unsupplied_energy_costs),
"seed-spilled-energy-costs": str(self.seed_spilled_energy_costs),
"seed-thermal-costs": str(self.seed_thermal_costs),
"seed-hydro-costs": str(self.seed_hydro_costs),
"seed-initial-reservoir-levels": str(self.seed_initial_reservoir_levels),
},
}


@dataclass
class SeedParameters:
seed_tsgen_thermal: Optional[int] = None
seed_tsnumbers: Optional[int] = None
seed_unsupplied_energy_costs: Optional[int] = None
seed_spilled_energy_costs: Optional[int] = None
seed_thermal_costs: Optional[int] = None
seed_hydro_costs: Optional[int] = None
seed_initial_reservoir_levels: Optional[int] = None
140 changes: 42 additions & 98 deletions src/antares/craft/model/settings/general.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,44 +9,40 @@
# SPDX-License-Identifier: MPL-2.0
#
# This file is part of the Antares project.
from dataclasses import dataclass
from typing import Optional

import typing as t

from antares.craft.tools.all_optional_meta import all_optional_model
from antares.craft.tools.contents_tool import EnumIgnoreCase
from pydantic import BaseModel, ConfigDict, Field, field_validator
from pydantic.alias_generators import to_camel


class Mode(EnumIgnoreCase):
ECONOMY = "economy"
ADEQUACY = "adequacy"
DRAFT = "draft"
ECONOMY = "Economy"
ADEQUACY = "Adequacy"


class Month(EnumIgnoreCase):
JANUARY = "january"
FEBRUARY = "february"
MARCH = "march"
APRIL = "april"
MAY = "may"
JUNE = "june"
JULY = "july"
AUGUST = "august"
SEPTEMBER = "september"
OCTOBER = "october"
NOVEMBER = "november"
DECEMBER = "december"
JANUARY = "January"
FEBRUARY = "February"
MARCH = "March"
APRIL = "April"
MAY = "May"
JUNE = "June"
JULY = "July"
AUGUST = "August"
SEPTEMBER = "September"
OCTOBER = "October"
NOVEMBER = "November"
DECEMBER = "December"


class WeekDay(EnumIgnoreCase):
MONDAY = "monday"
TUESDAY = "tuesday"
WEDNESDAY = "wednesday"
THURSDAY = "thursday"
FRIDAY = "friday"
SATURDAY = "saturday"
SUNDAY = "sunday"
MONDAY = "Monday"
TUESDAY = "Tuesday"
WEDNESDAY = "Wednesday"
THURSDAY = "Thursday"
FRIDAY = "Friday"
SATURDAY = "Saturday"
SUNDAY = "Sunday"


class BuildingMode(EnumIgnoreCase):
Expand All @@ -71,74 +67,22 @@ class OutputFormat(EnumIgnoreCase):
ZIP = "zip-files"


class DefaultGeneralParameters(BaseModel, extra="forbid", populate_by_name=True, alias_generator=to_camel):
model_config = ConfigDict(use_enum_values=True)

mode: Mode = Field(default=Mode.ECONOMY, validate_default=True)
horizon: str = ""
# Calendar parameters
nb_years: int = 1
first_day: int = 1
last_day: int = 365
first_january: WeekDay = Field(default=WeekDay.MONDAY, validate_default=True)
first_month: Month = Field(default=Month.JANUARY, validate_default=True)
first_week_day: WeekDay = Field(default=WeekDay.MONDAY, validate_default=True)
leap_year: bool = False
# Additional parameters
year_by_year: bool = False
building_mode: BuildingMode = Field(
default=BuildingMode.AUTOMATIC, validate_default=True
) # ? derated and custom-scenario
selection_mode: bool = False # ? user-playlist
thematic_trimming: bool = False
geographic_trimming: bool = False
active_rules_scenario: str = "default ruleset" # only one option available currently
read_only: bool = False
# Output parameters
simulation_synthesis: bool = True # ? output/synthesis
mc_scenario: bool = False # ? output/storenewset
result_format: OutputFormat = Field(default=OutputFormat.TXT, exclude=True)

@field_validator("horizon", mode="before")
def transform_horizon_to_str(cls, val: t.Union[str, int, None]) -> t.Optional[str]:
# horizon can be an int.
return str(val) if val else val # type: ignore


@all_optional_model
class GeneralParameters(DefaultGeneralParameters):
pass


class GeneralParametersLocal(DefaultGeneralParameters):
@property
def ini_fields(self) -> dict:
return {
"general": {
"mode": str(self.mode).title(),
"horizon": self.horizon,
"nbyears": str(self.nb_years),
"simulation.start": str(self.first_day),
"simulation.end": str(self.last_day),
"january.1st": str(self.first_january).title(),
"first-month-in-year": str(self.first_month).title(),
"first.weekday": str(self.first_week_day).title(),
"leapyear": str(self.leap_year).lower(),
"year-by-year": str(self.year_by_year).lower(),
"derated": str(self.building_mode == BuildingMode.DERATED).lower(),
"custom-scenario": str(self.building_mode == BuildingMode.CUSTOM).lower(),
"user-playlist": str(self.selection_mode).lower(),
"thematic-trimming": str(self.thematic_trimming).lower(),
"geographic-trimming": str(self.geographic_trimming).lower(),
"readonly": str(self.read_only).lower(),
},
"input": {},
"output": {
"synthesis": str(self.simulation_synthesis).lower(),
"storenewset": str(self.mc_scenario).lower(),
"result-format": self.result_format.value,
},
}

def yield_properties(self) -> GeneralParameters:
return GeneralParameters.model_validate(self.model_dump(exclude_none=True))
@dataclass
class GeneralParameters:
mode: Optional[Mode] = None
horizon: Optional[str] = None
nb_years: Optional[int] = None
simulation_start: Optional[int] = None
simulation_end: Optional[int] = None
january_first: Optional[WeekDay] = None
first_month_in_year: Optional[Month] = None
first_week_day: Optional[WeekDay] = None
leap_year: Optional[bool] = None
year_by_year: Optional[bool] = None
simulation_synthesis: Optional[bool] = None
building_mode: Optional[BuildingMode] = None
user_playlist: Optional[bool] = None
thematic_trimming: Optional[bool] = None
geographic_trimming: Optional[bool] = None
store_new_set: Optional[bool] = None
nb_timeseries_thermal: Optional[int] = None
Loading