diff --git a/antarest/study/business/adequacy_patch_management.py b/antarest/study/business/adequacy_patch_management.py index 26dc1ec548..845c1fc0f4 100644 --- a/antarest/study/business/adequacy_patch_management.py +++ b/antarest/study/business/adequacy_patch_management.py @@ -17,7 +17,7 @@ from antarest.study.business.all_optional_meta import all_optional_model from antarest.study.business.enum_ignore_case import EnumIgnoreCase from antarest.study.business.utils import GENERAL_DATA_PATH, FieldInfo, FormFieldsBaseModel, execute_or_add_commands -from antarest.study.model import STUDY_VERSION_8_3, STUDY_VERSION_8_5, Study +from antarest.study.model import STUDY_VERSION_8_3, STUDY_VERSION_8_5, STUDY_VERSION_9_2, Study from antarest.study.storage.storage_service import StudyStorageService from antarest.study.storage.variantstudy.model.command.update_config import UpdateConfig @@ -63,6 +63,7 @@ class AdequacyPatchFormFields(FormFieldsBaseModel): "path": f"{ADEQUACY_PATCH_PATH}/set-to-null-ntc-between-physical-out-for-first-step", "default_value": True, "start_version": STUDY_VERSION_8_3, + "end_version": STUDY_VERSION_9_2, }, "price_taking_order": { "path": f"{ADEQUACY_PATCH_PATH}/price-taking-order", @@ -111,9 +112,10 @@ def get_field_values(self, study: Study) -> AdequacyPatchFormFields: def get_value(field_info: FieldInfo) -> Any: path = field_info["path"] - start_version = field_info.get("start_version", -1) + start_version = field_info.get("start_version", 0) + end_version = field_info.get("end_version", 100000) target_name = path.split("/")[-1] - is_in_version = file_study.config.version >= start_version + is_in_version = file_study.config.version >= start_version and file_study.config.version < end_version return parent.get(target_name, field_info["default_value"]) if is_in_version else None diff --git a/antarest/study/business/advanced_parameters_management.py b/antarest/study/business/advanced_parameters_management.py index 87f6939a91..7b1cf7c5fa 100644 --- a/antarest/study/business/advanced_parameters_management.py +++ b/antarest/study/business/advanced_parameters_management.py @@ -20,7 +20,7 @@ from antarest.study.business.all_optional_meta import all_optional_model from antarest.study.business.enum_ignore_case import EnumIgnoreCase from antarest.study.business.utils import GENERAL_DATA_PATH, FieldInfo, FormFieldsBaseModel, execute_or_add_commands -from antarest.study.model import STUDY_VERSION_8_8, Study +from antarest.study.model import STUDY_VERSION_8_8, STUDY_VERSION_9_2, Study from antarest.study.storage.storage_service import StudyStorageService from antarest.study.storage.variantstudy.model.command.update_config import UpdateConfig @@ -100,6 +100,7 @@ class AdvancedParamsFormFields(FormFieldsBaseModel): seed_thermal_costs: StrictInt seed_hydro_costs: StrictInt seed_initial_reservoir_levels: StrictInt + hydro_pmax_format: str @field_validator("accuracy_on_correlation") def check_accuracy_on_correlation(cls, v: str) -> str: @@ -134,6 +135,7 @@ def check_accuracy_on_correlation(cls, v: str) -> str: "initial_reservoir_levels": { "path": f"{OTHER_PREFERENCES_PATH}/initial-reservoir-levels", "default_value": InitialReservoirLevel.COLD_START.value, + "end_version": STUDY_VERSION_9_2, }, "power_fluctuations": { "path": f"{OTHER_PREFERENCES_PATH}/power-fluctuations", @@ -212,6 +214,11 @@ def check_accuracy_on_correlation(cls, v: str) -> str: "path": f"{SEEDS_PATH}/seed-initial-reservoir-levels", "default_value": 10005489, }, + "hydro_pmax_format": { + "path": f"{OTHER_PREFERENCES_PATH}/hydro-pmax-format", + "default_value": "daily", + "start_version": STUDY_VERSION_9_2, + }, } @@ -230,14 +237,19 @@ def get_field_values(self, study: Study) -> AdvancedParamsFormFields: seeds = general_data.get("seeds - Mersenne Twister", {}) def get_value(field_info: FieldInfo) -> Any: + start_version = field_info.get("start_version", 0) + end_version = field_info.get("end_version", 100000) + is_in_version = file_study.config.version >= start_version and file_study.config.version < end_version + if not is_in_version: + return None path = field_info["path"] - target_name = path.split("/")[-1] if ADVANCED_PARAMS_PATH in path: parent = advanced_params elif OTHER_PREFERENCES_PATH in path: parent = other_preferences else: parent = seeds + target_name = path.split("/")[-1] return parent.get(target_name, field_info["default_value"]) return AdvancedParamsFormFields.construct(**{name: get_value(info) for name, info in FIELDS_INFO.items()}) diff --git a/antarest/study/business/areas/st_storage_management.py b/antarest/study/business/areas/st_storage_management.py index 7592d50423..62d5a7ba5e 100644 --- a/antarest/study/business/areas/st_storage_management.py +++ b/antarest/study/business/areas/st_storage_management.py @@ -35,8 +35,8 @@ from antarest.study.model import STUDY_VERSION_8_8, Study from antarest.study.storage.rawstudy.model.filesystem.config.model import transform_name_to_id from antarest.study.storage.rawstudy.model.filesystem.config.st_storage import ( - STStorage880Config, - STStorage880Properties, + STStorage920Config, + STStorage920Properties, STStorageConfigType, STStorageGroup, create_st_storage_config, @@ -51,7 +51,7 @@ @all_optional_model @camel_case_model -class STStorageInput(STStorage880Properties): +class STStorageInput(STStorage920Properties): """ Model representing the form used to EDIT an existing short-term storage. """ @@ -94,7 +94,7 @@ def to_config(self, study_version: StudyVersion) -> STStorageConfigType: @all_optional_model @camel_case_model -class STStorageOutput(STStorage880Config): +class STStorageOutput(STStorage920Config): """ Model representing the form used to display the details of a short-term storage entry. """ @@ -303,7 +303,7 @@ def create_storage( def _make_create_cluster_cmd(self, area_id: str, cluster: STStorageConfigType) -> CreateSTStorage: command = CreateSTStorage( area_id=area_id, - parameters=cluster, + parameters=cluster.model_dump(mode="json", by_alias=True, exclude_none=True), command_context=self.storage_service.variant_study_service.command_factory.command_context, ) return command diff --git a/antarest/study/business/thematic_trimming_field_infos.py b/antarest/study/business/thematic_trimming_field_infos.py index 9b2e0b06be..e4aa00b8c9 100644 --- a/antarest/study/business/thematic_trimming_field_infos.py +++ b/antarest/study/business/thematic_trimming_field_infos.py @@ -20,11 +20,17 @@ from antarest.study.business.all_optional_meta import all_optional_model from antarest.study.business.utils import FormFieldsBaseModel -from antarest.study.model import STUDY_VERSION_8_1, STUDY_VERSION_8_3, STUDY_VERSION_8_6, STUDY_VERSION_8_8 +from antarest.study.model import ( + STUDY_VERSION_8_1, + STUDY_VERSION_8_3, + STUDY_VERSION_8_6, + STUDY_VERSION_8_8, + STUDY_VERSION_9_1, +) @all_optional_model -class ThematicTrimmingFormFields(FormFieldsBaseModel): +class ThematicTrimmingFormFieldsBase(FormFieldsBaseModel): """ This class manages the configuration of result filtering in a simulation. @@ -96,6 +102,10 @@ class ThematicTrimmingFormFields(FormFieldsBaseModel): # since v8.3 dens: bool profit_by_plant: bool + + +@all_optional_model +class ThematicTrimmingFormFields860(ThematicTrimmingFormFieldsBase): # topic: Short-Term Storages # since v8.6 sts_inj_by_plant: bool @@ -132,6 +142,34 @@ class ThematicTrimmingFormFields(FormFieldsBaseModel): other5_level: bool +@all_optional_model +class ThematicTrimmingFormFields910(ThematicTrimmingFormFieldsBase): + sts_inj_by_plant: bool + sts_withdrawal_by_plant: bool + sts_lvl_by_plant: bool + sts_cashflow_by_cluster: bool + sts_by_group: bool + + +ThematicTrimmingFormFieldsType = t.Union[ + ThematicTrimmingFormFields910, ThematicTrimmingFormFields860, ThematicTrimmingFormFieldsBase +] + + +def get_thematic_trimming_cls(study_version: StudyVersion) -> t.Type[ThematicTrimmingFormFieldsType]: + if study_version >= STUDY_VERSION_9_1: + return ThematicTrimmingFormFields910 + elif study_version >= STUDY_VERSION_8_6: + return ThematicTrimmingFormFields860 + else: + return ThematicTrimmingFormFieldsBase + + +def create_thematic_trimming_config(study_version: StudyVersion, **kwargs: t.Any) -> ThematicTrimmingFormFieldsType: + cls = get_thematic_trimming_cls(study_version) + return cls.model_validate(kwargs) + + _GENERAL = "General" _SHORT_TERM_STORAGES = "Short-Term Storages" _SHORT_TERM_STORAGES_GROUP = "Short-Term Storages - Group" @@ -210,40 +248,50 @@ class ThematicTrimmingFormFields(FormFieldsBaseModel): "sts_lvl_by_plant": {"topic": _SHORT_TERM_STORAGES, "path": "STS lvl by plant", "default_value": True, "start_version": STUDY_VERSION_8_6}, "sts_cashflow_by_cluster": {"topic": _SHORT_TERM_STORAGES, "path": "STS Cashflow By Cluster", "default_value": True, "start_version": STUDY_VERSION_8_8}, # topic: "Short-Term Storages - Group" - "psp_open_injection": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "PSP_open_injection", "default_value": True, "start_version": STUDY_VERSION_8_6}, - "psp_open_withdrawal": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "PSP_open_withdrawal", "default_value": True, "start_version": STUDY_VERSION_8_6}, - "psp_open_level": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "PSP_open_level", "default_value": True, "start_version": STUDY_VERSION_8_6}, - "psp_closed_injection": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "PSP_closed_injection", "default_value": True, "start_version": STUDY_VERSION_8_6}, - "psp_closed_withdrawal": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "PSP_closed_withdrawal", "default_value": True, "start_version": STUDY_VERSION_8_6}, - "psp_closed_level": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "PSP_closed_level", "default_value": True, "start_version": STUDY_VERSION_8_6}, - "pondage_injection": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Pondage_injection", "default_value": True, "start_version": STUDY_VERSION_8_6}, - "pondage_withdrawal": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Pondage_withdrawal", "default_value": True, "start_version": STUDY_VERSION_8_6}, - "pondage_level": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Pondage_level", "default_value": True, "start_version": STUDY_VERSION_8_6}, - "battery_injection": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Battery_injection", "default_value": True, "start_version": STUDY_VERSION_8_6}, - "battery_withdrawal": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Battery_withdrawal", "default_value": True, "start_version": STUDY_VERSION_8_6}, - "battery_level": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Battery_level", "default_value": True, "start_version": STUDY_VERSION_8_6}, - "other1_injection": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other1_injection", "default_value": True, "start_version": STUDY_VERSION_8_6}, - "other1_withdrawal": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other1_withdrawal", "default_value": True, "start_version": STUDY_VERSION_8_6}, - "other1_level": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other1_level", "default_value": True, "start_version": STUDY_VERSION_8_6}, - "other2_injection": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other2_injection", "default_value": True, "start_version": STUDY_VERSION_8_6}, - "other2_withdrawal": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other2_withdrawal", "default_value": True, "start_version": STUDY_VERSION_8_6}, - "other2_level": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other2_level", "default_value": True, "start_version": STUDY_VERSION_8_6}, - "other3_injection": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other3_injection", "default_value": True, "start_version": STUDY_VERSION_8_6}, - "other3_withdrawal": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other3_withdrawal", "default_value": True, "start_version": STUDY_VERSION_8_6}, - "other3_level": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other3_level", "default_value": True, "start_version": STUDY_VERSION_8_6}, - "other4_injection": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other4_injection", "default_value": True, "start_version": STUDY_VERSION_8_6}, - "other4_withdrawal": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other4_withdrawal", "default_value": True, "start_version": STUDY_VERSION_8_6}, - "other4_level": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other4_level", "default_value": True, "start_version": STUDY_VERSION_8_6}, - "other5_injection": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other5_injection", "default_value": True, "start_version": STUDY_VERSION_8_6}, - "other5_withdrawal": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other5_withdrawal", "default_value": True, "start_version": STUDY_VERSION_8_6}, - "other5_level": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other5_level", "default_value": True, "start_version": STUDY_VERSION_8_6}, + "psp_open_injection": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "PSP_open_injection", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, + "psp_open_withdrawal": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "PSP_open_withdrawal", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, + "psp_open_level": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "PSP_open_level", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, + "psp_closed_injection": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "PSP_closed_injection", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, + "psp_closed_withdrawal": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "PSP_closed_withdrawal", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, + "psp_closed_level": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "PSP_closed_level", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, + "pondage_injection": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Pondage_injection", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, + "pondage_withdrawal": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Pondage_withdrawal", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, + "pondage_level": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Pondage_level", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, + "battery_injection": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Battery_injection", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, + "battery_withdrawal": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Battery_withdrawal", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, + "battery_level": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Battery_level", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, + "other1_injection": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other1_injection", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, + "other1_withdrawal": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other1_withdrawal", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, + "other1_level": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other1_level", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, + "other2_injection": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other2_injection", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, + "other2_withdrawal": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other2_withdrawal", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, + "other2_level": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other2_level", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, + "other3_injection": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other3_injection", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, + "other3_withdrawal": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other3_withdrawal", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, + "other3_level": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other3_level", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, + "other4_injection": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other4_injection", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, + "other4_withdrawal": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other4_withdrawal", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, + "other4_level": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other4_level", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, + "other5_injection": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other5_injection", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, + "other5_withdrawal": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other5_withdrawal", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, + "other5_level": {"topic": _SHORT_TERM_STORAGES_GROUP, "path": "Other5_level", "default_value": True, "start_version": STUDY_VERSION_8_6, "end_version": STUDY_VERSION_9_1}, # fmt: on + # since v9.1 + "sts_by_group": { + "topic": _SHORT_TERM_STORAGES_GROUP, + "path": "STS by group", + "default_value": True, + "start_version": STUDY_VERSION_9_1, + }, } def get_fields_info(study_version: StudyVersion) -> t.Mapping[str, t.Mapping[str, t.Any]]: + highest_version = StudyVersion.parse(10000000) + lowest_version = StudyVersion.parse(0) return { key: info for key, info in FIELDS_INFO.items() - if (info.get("start_version") or StudyVersion.parse(0)) <= study_version + if info.get("start_version", lowest_version) <= study_version + and info.get("end_version", highest_version) > study_version } diff --git a/antarest/study/business/thematic_trimming_management.py b/antarest/study/business/thematic_trimming_management.py index 96fd8aa106..6ad9d0ddaa 100644 --- a/antarest/study/business/thematic_trimming_management.py +++ b/antarest/study/business/thematic_trimming_management.py @@ -14,7 +14,12 @@ from antares.study.version import StudyVersion -from antarest.study.business.thematic_trimming_field_infos import ThematicTrimmingFormFields, get_fields_info +from antarest.study.business.thematic_trimming_field_infos import ( + ThematicTrimmingFormFieldsType, + create_thematic_trimming_config, + get_fields_info, + get_thematic_trimming_cls, +) from antarest.study.business.utils import GENERAL_DATA_PATH, execute_or_add_commands from antarest.study.model import Study from antarest.study.storage.storage_service import StudyStorageService @@ -25,7 +30,7 @@ class ThematicTrimmingManager: def __init__(self, storage_service: StudyStorageService) -> None: self.storage_service = storage_service - def get_field_values(self, study: Study) -> ThematicTrimmingFormFields: + def get_field_values(self, study: Study) -> ThematicTrimmingFormFieldsType: """ Get Thematic Trimming field values for the webapp form """ @@ -44,14 +49,15 @@ def get_value(field_info: t.Mapping[str, t.Any]) -> bool: fields_info = get_fields_info(StudyVersion.parse(study.version)) fields_values = {name: get_value(info) for name, info in fields_info.items()} - return ThematicTrimmingFormFields(**fields_values) + return create_thematic_trimming_config(StudyVersion.parse(study.version), **fields_values) - def set_field_values(self, study: Study, field_values: ThematicTrimmingFormFields) -> None: + def set_field_values(self, study: Study, field_values: ThematicTrimmingFormFieldsType) -> None: """ Set Thematic Trimming config from the webapp form """ file_study = self.storage_service.get_storage(study).get_raw(study) - field_values_dict = field_values.model_dump() + cls = get_thematic_trimming_cls(StudyVersion.parse(study.version)) + field_values_dict = cls.model_validate(field_values).model_dump() keys_by_bool: t.Dict[bool, t.List[t.Any]] = {True: [], False: []} fields_info = get_fields_info(StudyVersion.parse(study.version)) diff --git a/antarest/study/model.py b/antarest/study/model.py index fbeefef1f4..e8c92f5b20 100644 --- a/antarest/study/model.py +++ b/antarest/study/model.py @@ -81,6 +81,7 @@ STUDY_VERSION_8_6: "empty_study_860.zip", STUDY_VERSION_8_7: "empty_study_870.zip", STUDY_VERSION_8_8: "empty_study_880.zip", + STUDY_VERSION_9_2: "empty_study_920.zip", } diff --git a/antarest/study/storage/rawstudy/model/filesystem/config/st_storage.py b/antarest/study/storage/rawstudy/model/filesystem/config/st_storage.py index 426e263baa..129a6b6a9b 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/config/st_storage.py +++ b/antarest/study/storage/rawstudy/model/filesystem/config/st_storage.py @@ -16,7 +16,7 @@ from pydantic import Field from antarest.study.business.enum_ignore_case import EnumIgnoreCase -from antarest.study.model import STUDY_VERSION_8_6, STUDY_VERSION_8_8 +from antarest.study.model import STUDY_VERSION_8_6, STUDY_VERSION_8_8, STUDY_VERSION_9_2 from antarest.study.storage.rawstudy.model.filesystem.config.cluster import ItemProperties from antarest.study.storage.rawstudy.model.filesystem.config.identifier import LowerCaseIdentifier @@ -114,6 +114,16 @@ class STStorage880Properties(STStorageProperties): enabled: bool = Field(default=True, description="Activity status") +class STStorage920Properties(STStorage880Properties): + """ + Short term storage configuration model for v9.2 study. + """ + + # Group can now take any value + group: str = Field("other 1") # type: ignore + efficiency_withdrawal: float = Field(1, ge=0, le=1, alias="efficiencywithdrawal") + + # noinspection SpellCheckingInspection class STStorageConfig(STStorageProperties, LowerCaseIdentifier): """ @@ -158,9 +168,15 @@ class STStorage880Config(STStorage880Properties, LowerCaseIdentifier): """ -# NOTE: In the following Union, it is important to place the older version first, -# because otherwise, creating a short term storage always creates a v8.8 one. -STStorageConfigType = t.Union[STStorageConfig, STStorage880Config] +class STStorage920Config(STStorage920Properties, LowerCaseIdentifier): + """ + Short Term Storage properties for study in version 9.2 or above. + """ + + +# todo: The v9.2 has the field group as a string, so the pydantic validation for this union can choose the v9.2 config. +# We'll have to implement a nice way to handle this in another PR +STStorageConfigType = t.Union[STStorageConfig, STStorage880Config, STStorage920Config] def get_st_storage_config_cls(study_version: StudyVersion) -> t.Type[STStorageConfigType]: @@ -173,7 +189,9 @@ def get_st_storage_config_cls(study_version: StudyVersion) -> t.Type[STStorageCo Returns: The short-term storage configuration class. """ - if study_version >= STUDY_VERSION_8_8: + if study_version >= STUDY_VERSION_9_2: + return STStorage920Config + elif study_version >= STUDY_VERSION_8_8: return STStorage880Config elif study_version >= STUDY_VERSION_8_6: return STStorageConfig diff --git a/antarest/study/storage/rawstudy/model/filesystem/config/thermal.py b/antarest/study/storage/rawstudy/model/filesystem/config/thermal.py index ff095c2b2e..6f6b4602d0 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/config/thermal.py +++ b/antarest/study/storage/rawstudy/model/filesystem/config/thermal.py @@ -16,6 +16,7 @@ from pydantic import Field from antarest.study.business.enum_ignore_case import EnumIgnoreCase +from antarest.study.model import STUDY_VERSION_8_6, STUDY_VERSION_8_7 from antarest.study.storage.rawstudy.model.filesystem.config.cluster import ClusterProperties from antarest.study.storage.rawstudy.model.filesystem.config.identifier import IgnoreCaseIdentifier @@ -416,9 +417,9 @@ def get_thermal_config_cls(study_version: StudyVersion) -> t.Type[ThermalConfigT Returns: The thermal configuration class. """ - if study_version >= 870: + if study_version >= STUDY_VERSION_8_7: return Thermal870Config - elif study_version == 860: + elif study_version == STUDY_VERSION_8_6: return Thermal860Config else: return ThermalConfig diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/area.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/area.py index a67fbf6dfc..d3e73022b2 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/area.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/area.py @@ -10,7 +10,7 @@ # # This file is part of the Antares project. -from antarest.study.model import STUDY_VERSION_8_2 +from antarest.study.model import STUDY_VERSION_8_2, STUDY_VERSION_9_2 from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.context import ContextServer from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode @@ -19,6 +19,7 @@ from antarest.study.storage.rawstudy.model.filesystem.root.input.link.area.capacities.capacities import ( InputLinkAreaCapacities, ) +from antarest.study.storage.rawstudy.model.filesystem.root.input.link.area.prepro.prepro import InputLinkAreaPrepro from antarest.study.storage.rawstudy.model.filesystem.root.input.link.area.properties import InputLinkAreaProperties @@ -50,5 +51,6 @@ def build(self) -> TREE: cfg.next_file("properties.ini"), area=self.area, ) - + if cfg.version >= STUDY_VERSION_9_2: + children["prepro"] = InputLinkAreaPrepro(ctx, cfg.next_file("prepro"), area=self.area) return children diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/prepro/__init__.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/prepro/__init__.py new file mode 100644 index 0000000000..058c6b221a --- /dev/null +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/prepro/__init__.py @@ -0,0 +1,11 @@ +# 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. diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/prepro/prepro.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/prepro/prepro.py new file mode 100644 index 0000000000..bbfea7387c --- /dev/null +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/prepro/prepro.py @@ -0,0 +1,45 @@ +# 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 antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig +from antarest.study.storage.rawstudy.model.filesystem.context import ContextServer +from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode +from antarest.study.storage.rawstudy.model.filesystem.inode import TREE +from antarest.study.storage.rawstudy.model.filesystem.matrix.input_series_matrix import InputSeriesMatrix + + +class InputLinkAreaPrepro(FolderNode): + def __init__( + self, + context: ContextServer, + config: FileStudyTreeConfig, + area: str, + ): + super().__init__(context, config) + self.area = area + + def build(self) -> TREE: + children: TREE = {} + for area_to in self.config.get_links(self.area): + children[f"{area_to}_direct"] = InputSeriesMatrix( + self.context, + self.config.next_file(f"{area_to}_direct.txt"), + ) + children[f"{area_to}_indirect"] = InputSeriesMatrix( + self.context, + self.config.next_file(f"{area_to}_indirect.txt"), + ) + children[f"{area_to}_mod"] = InputSeriesMatrix( + self.context, + self.config.next_file(f"{area_to}_mod.txt"), + ) + return children diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/series/area/st_storage/st_storage.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/series/area/st_storage/st_storage.py index a531bd4bee..2954e5fa7c 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/series/area/st_storage/st_storage.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/series/area/st_storage/st_storage.py @@ -10,6 +10,7 @@ # # This file is part of the Antares project. +from antarest.study.model import STUDY_VERSION_9_2 from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE from antarest.study.storage.rawstudy.model.filesystem.matrix.input_series_matrix import InputSeriesMatrix @@ -45,4 +46,8 @@ def build(self) -> TREE: default_empty=series.upper_rule_curve, ), } + if self.config.version >= STUDY_VERSION_9_2: + children["cost_injection"] = InputSeriesMatrix(self.context, self.config.next_file("cost-injection.txt")) + children["cost_withdrawal"] = InputSeriesMatrix(self.context, self.config.next_file("cost-withdrawal.txt")) + children["cost_level"] = InputSeriesMatrix(self.context, self.config.next_file("cost-level.txt")) return children diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/settings/generaldata.py b/antarest/study/storage/rawstudy/model/filesystem/root/settings/generaldata.py index 27ece887bf..8d9db41ade 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/settings/generaldata.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/settings/generaldata.py @@ -24,6 +24,7 @@ STUDY_VERSION_8_4, STUDY_VERSION_8_5, STUDY_VERSION_8_6, + STUDY_VERSION_9_2, ) from antarest.study.storage.rawstudy.ini_reader import IniReader from antarest.study.storage.rawstudy.ini_writer import IniWriter @@ -167,6 +168,15 @@ def __init__(self, context: ContextServer, config: FileStudyTreeConfig): if study_version >= STUDY_VERSION_8_6: types["adequacy patch"]["enable-first-step "] = bool + if study_version >= STUDY_VERSION_9_2: + adequacy = types["adequacy patch"] + adequacy.pop("enable-first-step", None) + adequacy.pop("set-to-null-ntc-between-physical-out-for-first-step", None) + other_preferences = types["other preferences"] + other_preferences.pop("initial-reservoir-levels", None) + other_preferences["hydro-pmax-format"] = str + types["general"]["nbtimeserieslinks"] = float + IniFileNode.__init__( self, context, diff --git a/antarest/study/storage/study_upgrader/__init__.py b/antarest/study/storage/study_upgrader/__init__.py index e854e7d013..ea7526b155 100644 --- a/antarest/study/storage/study_upgrader/__init__.py +++ b/antarest/study/storage/study_upgrader/__init__.py @@ -20,7 +20,7 @@ from antarest.core.exceptions import UnsupportedStudyVersion -AVAILABLE_VERSIONS = ["700", "710", "720", "800", "810", "820", "830", "840", "850", "860", "870", "880"] +AVAILABLE_VERSIONS = ["700", "710", "720", "800", "810", "820", "830", "840", "850", "860", "870", "880", "920"] class InvalidUpgrade(HTTPException): diff --git a/antarest/study/storage/variantstudy/business/command_reverter.py b/antarest/study/storage/variantstudy/business/command_reverter.py index 5134a86bea..f64c5ccd3d 100644 --- a/antarest/study/storage/variantstudy/business/command_reverter.py +++ b/antarest/study/storage/variantstudy/business/command_reverter.py @@ -204,11 +204,10 @@ def _revert_create_st_storage( history: t.List["ICommand"], base: FileStudy, ) -> t.List[ICommand]: - storage_id = base_command.parameters.id return [ RemoveSTStorage( area_id=base_command.area_id, - storage_id=storage_id, + storage_id=base_command.storage_id, command_context=base_command.command_context, ) ] diff --git a/antarest/study/storage/variantstudy/model/command/create_st_storage.py b/antarest/study/storage/variantstudy/model/command/create_st_storage.py index 4bebf009c3..6ce371a291 100644 --- a/antarest/study/storage/variantstudy/model/command/create_st_storage.py +++ b/antarest/study/storage/variantstudy/model/command/create_st_storage.py @@ -9,7 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. - +import copy import typing as t import numpy as np @@ -18,8 +18,12 @@ from antarest.core.model import JSON from antarest.matrixstore.model import MatrixData from antarest.study.model import STUDY_VERSION_8_6 -from antarest.study.storage.rawstudy.model.filesystem.config.model import Area, FileStudyTreeConfig -from antarest.study.storage.rawstudy.model.filesystem.config.st_storage import STStorageConfigType +from antarest.study.storage.rawstudy.model.filesystem.config.model import ( + Area, + FileStudyTreeConfig, + transform_name_to_id, +) +from antarest.study.storage.rawstudy.model.filesystem.config.st_storage import create_st_storage_config from antarest.study.storage.rawstudy.model.filesystem.factory import FileStudy from antarest.study.storage.variantstudy.business.matrix_constants_generator import GeneratorMatrixConstants from antarest.study.storage.variantstudy.business.utils import strip_matrix_protocol, validate_matrix @@ -58,7 +62,7 @@ class CreateSTStorage(ICommand): # ================== area_id: str = Field(description="Area ID", pattern=r"[a-z0-9_(),& -]+") - parameters: STStorageConfigType + parameters: t.Dict[str, t.Any] pmax_injection: t.Optional[t.Union[MatrixType, str]] = Field( default=None, description="Charge capacity (modulation)", @@ -83,12 +87,21 @@ class CreateSTStorage(ICommand): @property def storage_id(self) -> str: """The normalized version of the storage's name used as the ID.""" - return self.parameters.id + return str(self.parameters["id"]) @property def storage_name(self) -> str: """The label representing the name of the storage for the user.""" - return self.parameters.name + return str(self.parameters["name"]) + + @model_validator(mode="after") + def validate_id(self) -> "CreateSTStorage": + storage_name = self.parameters["name"] + storage_id = transform_name_to_id(storage_name) + if not storage_id: + raise ValueError(f"Invalid name '{storage_name}'.") + self.parameters["id"] = storage_id + return self @staticmethod def validate_field( @@ -204,7 +217,7 @@ def _apply_config(self, study_data: FileStudyTreeConfig) -> t.Tuple[CommandOutpu ) # Create a new short-term storage and add it to the area - area.st_storages.append(self.parameters) + area.st_storages.append(create_st_storage_config(study_data.version, **self.parameters)) return ( CommandOutput( @@ -227,23 +240,24 @@ def _apply(self, study_data: FileStudy) -> CommandOutput: The output of the command execution. """ output, _ = self._apply_config(study_data.config) - if not output.status: - return output - - # Fill-in the "list.ini" file with the parameters. - # On creation, it's better to write all the parameters in the file. - config = study_data.tree.get(["input", "st-storage", "clusters", self.area_id, "list"]) - config[self.storage_id] = self.parameters.model_dump(mode="json", by_alias=True, exclude={"id"}) - - new_data: JSON = { - "input": { - "st-storage": { - "clusters": {self.area_id: {"list": config}}, - "series": {self.area_id: {self.storage_id: {attr: getattr(self, attr) for attr in _MATRIX_NAMES}}}, + if output.status: + # Fill-in the "list.ini" file with the parameters. + # On creation, it's better to write all the parameters in the file. + config = study_data.tree.get(["input", "st-storage", "clusters", self.area_id, "list"]) + storage_config = create_st_storage_config(study_data.config.version, **self.parameters) + config[self.storage_id] = storage_config.model_dump(mode="json", by_alias=True, exclude={"id"}) + + new_data: JSON = { + "input": { + "st-storage": { + "clusters": {self.area_id: {"list": config}}, + "series": { + self.area_id: {self.storage_id: {attr: getattr(self, attr) for attr in _MATRIX_NAMES}} + }, + } } } - } - study_data.tree.save(new_data) + study_data.tree.save(new_data) return output @@ -255,7 +269,8 @@ def to_dto(self) -> CommandDTO: Returns: The DTO object representing the current command. """ - parameters = self.parameters.model_dump(mode="json", by_alias=True, exclude={"id"}) + parameters = copy.deepcopy(self.parameters) + del parameters["id"] return CommandDTO( action=self.command_name.value, args={ @@ -320,11 +335,12 @@ def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: if getattr(self, attr) != getattr(other, attr) ] if self.parameters != other.parameters: - data: t.Dict[str, t.Any] = other.parameters.model_dump(mode="json", by_alias=True, exclude={"id"}) + args = copy.deepcopy(other.parameters) + del args["id"] commands.append( UpdateConfig( target=f"input/st-storage/clusters/{self.area_id}/list/{self.storage_id}", - data=data, + data=args, command_context=self.command_context, ) ) diff --git a/antarest/study/web/study_data_blueprint.py b/antarest/study/web/study_data_blueprint.py index 2128ed849c..aa84c7c10b 100644 --- a/antarest/study/web/study_data_blueprint.py +++ b/antarest/study/web/study_data_blueprint.py @@ -73,7 +73,7 @@ from antarest.study.business.playlist_management import PlaylistColumns from antarest.study.business.scenario_builder_management import Rulesets, ScenarioType from antarest.study.business.table_mode_management import TableDataDTO, TableModeType -from antarest.study.business.thematic_trimming_field_infos import ThematicTrimmingFormFields +from antarest.study.business.thematic_trimming_field_infos import ThematicTrimmingFormFieldsType from antarest.study.business.timeseries_config_management import TSFormFields from antarest.study.model import PatchArea, PatchCluster from antarest.study.service import StudyService @@ -554,13 +554,13 @@ def edit_matrix( "/studies/{uuid}/config/thematictrimming/form", tags=[APITag.study_data], summary="Get thematic trimming config", - response_model=ThematicTrimmingFormFields, + response_model=ThematicTrimmingFormFieldsType, response_model_exclude_none=True, ) def get_thematic_trimming( uuid: str, current_user: JWTUser = Depends(auth.get_current_user), - ) -> ThematicTrimmingFormFields: + ) -> ThematicTrimmingFormFieldsType: logger.info( f"Fetching thematic trimming config for study {uuid}", extra={"user": current_user.id}, @@ -576,7 +576,7 @@ def get_thematic_trimming( ) def set_thematic_trimming( uuid: str, - field_values: ThematicTrimmingFormFields, + field_values: ThematicTrimmingFormFieldsType, current_user: JWTUser = Depends(auth.get_current_user), ) -> None: logger.info( diff --git a/requirements.txt b/requirements.txt index e5f9d48cd1..acdbe8d581 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ -Antares-Launcher==1.4.2 -antares-study-version==1.0.6 +Antares-Launcher==1.4.3 +antares-study-version==1.0.8 antares-timeseries-generation~=0.1.5 # When you install `fastapi[all]`, you get FastAPI along with additional dependencies: diff --git a/tests/storage/study_upgrader/upgrade_800/nominal_case/empty_study_720.zip b/resources/empty_study_920.zip similarity index 82% rename from tests/storage/study_upgrader/upgrade_800/nominal_case/empty_study_720.zip rename to resources/empty_study_920.zip index b1eb6ee06f..99cf16fa7b 100644 Binary files a/tests/storage/study_upgrader/upgrade_800/nominal_case/empty_study_720.zip and b/resources/empty_study_920.zip differ diff --git a/tests/integration/study_data_blueprint/test_table_mode.py b/tests/integration/study_data_blueprint/test_table_mode.py index 98d7f03393..df85c7104d 100644 --- a/tests/integration/study_data_blueprint/test_table_mode.py +++ b/tests/integration/study_data_blueprint/test_table_mode.py @@ -645,6 +645,7 @@ def test_lifecycle__nominal( "efficiency", "initialLevel", "initialLevelOptim", + "efficiencyWithdrawal", # since v9.2 } # Prepare data for short-term storage tests @@ -702,6 +703,8 @@ def test_lifecycle__nominal( _it_storage3_values = {"group": "Pondage"} if study_version >= 880: _it_storage3_values["enabled"] = False + if study_version >= 920: + _it_storage3_values["efficiencyWithdrawal"] = 0.66 res = client.put( f"/v1/studies/{internal_study_id}/table-mode/st-storages", @@ -725,6 +728,7 @@ def test_lifecycle__nominal( "injectionNominalCapacity": 1550, "reservoirCapacity": 1500, "withdrawalNominalCapacity": 1550, + "efficiencyWithdrawal": None, }, "fr / tesla": { # "id": "tesla", @@ -737,6 +741,7 @@ def test_lifecycle__nominal( "injectionNominalCapacity": 1200, "reservoirCapacity": 1200, "withdrawalNominalCapacity": 1200, + "efficiencyWithdrawal": None, }, "it / storage3": { # "id": "storage3", @@ -749,6 +754,7 @@ def test_lifecycle__nominal( "injectionNominalCapacity": 1234, "reservoirCapacity": 1357, "withdrawalNominalCapacity": 1020, + "efficiencyWithdrawal": None, }, "it / storage4": { # "id": "storage4", @@ -761,6 +767,7 @@ def test_lifecycle__nominal( "injectionNominalCapacity": 567, "reservoirCapacity": 500, "withdrawalNominalCapacity": 456, + "efficiencyWithdrawal": None, }, } @@ -768,6 +775,10 @@ def test_lifecycle__nominal( for key in expected: expected[key]["enabled"] = True expected["it / storage3"]["enabled"] = False + if study_version >= 920: + for key in expected: + expected[key]["efficiencyWithdrawal"] = 1 + expected["it / storage3"]["efficiencyWithdrawal"] = 0.66 assert actual == expected diff --git a/tests/storage/business/test_config_manager.py b/tests/storage/business/test_config_manager.py index fa9e3b887a..733ada07fa 100644 --- a/tests/storage/business/test_config_manager.py +++ b/tests/storage/business/test_config_manager.py @@ -15,12 +15,13 @@ from antares.study.version import StudyVersion -from antarest.study.business.thematic_trimming_field_infos import FIELDS_INFO -from antarest.study.business.thematic_trimming_management import ( - ThematicTrimmingFormFields, - ThematicTrimmingManager, - get_fields_info, +from antarest.study.business.thematic_trimming_field_infos import ( + FIELDS_INFO, + ThematicTrimmingFormFields860, + ThematicTrimmingFormFields910, + ThematicTrimmingFormFieldsBase, ) +from antarest.study.business.thematic_trimming_management import ThematicTrimmingManager, get_fields_info from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.factory import FileStudy from antarest.study.storage.rawstudy.model.filesystem.root.filestudytree import FileStudyTree @@ -64,32 +65,36 @@ def test_thematic_trimming_config() -> None: {"variables selection": {"selected_vars_reset": True, "select_var -": ["DENS", "Profit by plant"]}}, # For study version >= 840: {"variables selection": {"selected_vars_reset": False, "select_var +": ["CONG. FEE (ALG.)"]}}, + # For study version >= 860: + {"variables selection": {"selected_vars_reset": True, "select_var -": ["STS inj by plant"]}}, + # For study version >= 910: + {"variables selection": {"selected_vars_reset": True, "select_var -": ["STS by group"]}}, ] study.version = config.version = 700 actual = thematic_trimming_manager.get_field_values(study) fields_info = get_fields_info(StudyVersion.parse(study.version)) - expected = ThematicTrimmingFormFields(**dict.fromkeys(fields_info, True)) + expected = ThematicTrimmingFormFieldsBase.model_validate(dict.fromkeys(fields_info, True)) assert actual == expected study.version = config.version = 800 actual = thematic_trimming_manager.get_field_values(study) fields_info = get_fields_info(StudyVersion.parse(study.version)) - expected = ThematicTrimmingFormFields(**dict.fromkeys(fields_info, True)) + expected = ThematicTrimmingFormFieldsBase.model_validate(dict.fromkeys(fields_info, True)) expected.avl_dtg = False assert actual == expected study.version = config.version = 820 actual = thematic_trimming_manager.get_field_values(study) fields_info = get_fields_info(StudyVersion.parse(study.version)) - expected = ThematicTrimmingFormFields(**dict.fromkeys(fields_info, True)) + expected = ThematicTrimmingFormFieldsBase.model_validate(dict.fromkeys(fields_info, True)) expected.avl_dtg = False assert actual == expected study.version = config.version = 830 actual = thematic_trimming_manager.get_field_values(study) fields_info = get_fields_info(StudyVersion.parse(study.version)) - expected = ThematicTrimmingFormFields(**dict.fromkeys(fields_info, True)) + expected = ThematicTrimmingFormFieldsBase.model_validate(dict.fromkeys(fields_info, True)) expected.dens = False expected.profit_by_plant = False assert actual == expected @@ -97,11 +102,11 @@ def test_thematic_trimming_config() -> None: study.version = config.version = 840 actual = thematic_trimming_manager.get_field_values(study) fields_info = get_fields_info(StudyVersion.parse(study.version)) - expected = ThematicTrimmingFormFields(**dict.fromkeys(fields_info, False)) + expected = ThematicTrimmingFormFieldsBase.model_validate(dict.fromkeys(fields_info, False)) expected.cong_fee_alg = True assert actual == expected - new_config = ThematicTrimmingFormFields(**dict.fromkeys(fields_info, True)) + new_config = ThematicTrimmingFormFieldsBase.model_validate(dict.fromkeys(fields_info, True)) new_config.coal = False thematic_trimming_manager.set_field_values(study, new_config) assert variant_study_service.append_commands.called_with( @@ -112,7 +117,7 @@ def test_thematic_trimming_config() -> None: ) ) - new_config = ThematicTrimmingFormFields(**dict.fromkeys(fields_info, False)) + new_config = ThematicTrimmingFormFieldsBase.model_validate(dict.fromkeys(fields_info, False)) new_config.renw_1 = True thematic_trimming_manager.set_field_values(study, new_config) assert variant_study_service.append_commands.called_with( @@ -126,4 +131,18 @@ def test_thematic_trimming_config() -> None: ) ) - assert len(FIELDS_INFO) == 94 + assert len(FIELDS_INFO) == 95 + + study.version = config.version = 860 + actual = thematic_trimming_manager.get_field_values(study) + fields_info = get_fields_info(StudyVersion.parse(study.version)) + expected = ThematicTrimmingFormFields860.model_validate(dict.fromkeys(fields_info, True)) + expected.sts_inj_by_plant = False + assert actual == expected + + study.version = config.version = 910 + actual = thematic_trimming_manager.get_field_values(study) + fields_info = get_fields_info(StudyVersion.parse(study.version)) + expected = ThematicTrimmingFormFields910.model_validate(dict.fromkeys(fields_info, True)) + expected.sts_by_group = False + assert actual == expected diff --git a/tests/storage/business/test_study_version_upgrader.py b/tests/storage/business/test_study_version_upgrader.py index 39ce1da653..ca46aa9764 100644 --- a/tests/storage/business/test_study_version_upgrader.py +++ b/tests/storage/business/test_study_version_upgrader.py @@ -55,7 +55,7 @@ def test_find_next_version_nominal(self, from_version: str, expected: str): "from_version, message", [ ("3.14", "Version '3.14' isn't among supported versions"), - ("880", "Your study is already in the latest supported version: '880'"), + ("920", "Your study is already in the latest supported version: '920'"), ("900", "Version '900' isn't among supported versions"), ], ) diff --git a/tests/storage/study_upgrader/conftest.py b/tests/storage/study_upgrader/conftest.py deleted file mode 100644 index 4e17e64e22..0000000000 --- a/tests/storage/study_upgrader/conftest.py +++ /dev/null @@ -1,77 +0,0 @@ -# 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. - -import typing -import zipfile -from pathlib import Path - -import pytest - - -class AssetNotFoundError(FileNotFoundError): - def __init__(self, asset_dir: Path, reason: str): - msg = ( - f"Asset not found in '{asset_dir}': {reason}." - f"\nMake sure that the resource files are available in the unit tests" - f" and that you have named them correctly according to the module" - f" name and the test function name (without the `test_` prefix)." - ) - super().__init__(msg) - - -class StudyAssets(typing.NamedTuple): - study_dir: Path - expected_dir: Path - - -@pytest.fixture(name="study_assets", scope="function") -def study_assets( - request: pytest.FixtureRequest, - tmp_path: Path, -) -> StudyAssets: - """ - Fixture that provides study assets for a test function. - Extract `{study}.zip` and `{study}.expected.zip` assets in the temporary path. - - Args: - request: Fixture request object for the test function. - tmp_path: Path to a temporary directory for the test session. - - Returns: - StudyAssets: An object that contains the paths to directories - for the study and expected study assets. - - Raises: - AssetNotFoundError: If the study or expected study assets are not found - in the resource directory. - """ - module_path = Path(request.fspath) - assets_dir = module_path.parent.joinpath(module_path.stem.replace("test_", "")) - asset_dir = assets_dir.joinpath(request.node.name.replace("test_", "")) - zip_files = list(asset_dir.glob("*.zip")) - # find the study ZIP and uncompress it - try: - zip_path = next(iter(p for p in zip_files if p.suffixes == [".zip"])) - except StopIteration: - raise AssetNotFoundError(asset_dir, "no '{study}.zip' file") from None - study_dir = tmp_path.joinpath(zip_path.stem) - with zipfile.ZipFile(zip_path) as zf: - zf.extractall(study_dir) - # find the expected study ZIP and uncompress it - try: - zip_path = next(iter(p for p in zip_files if p.suffixes == [".expected", ".zip"])) - except StopIteration: - raise AssetNotFoundError(asset_dir, "no '{study}.expected.zip' file") from None - expected_dir = tmp_path.joinpath(zip_path.stem) - with zipfile.ZipFile(zip_path) as zf: - zf.extractall(expected_dir) - return StudyAssets(study_dir, expected_dir) diff --git a/tests/storage/study_upgrader/test_upgrade_710.py b/tests/storage/study_upgrader/test_upgrade_710.py deleted file mode 100644 index 33763594b8..0000000000 --- a/tests/storage/study_upgrader/test_upgrade_710.py +++ /dev/null @@ -1,32 +0,0 @@ -# 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 antarest.study.storage.rawstudy.ini_reader import IniReader -from antarest.study.storage.study_upgrader import StudyUpgrader -from tests.storage.study_upgrader.conftest import StudyAssets - - -def test_nominal_case(study_assets: StudyAssets): - """ - Check that `settings/generaldata.ini` is upgraded to version 710. - """ - - # upgrade the study - study_upgrader = StudyUpgrader(study_assets.study_dir, "710") - study_upgrader.upgrade() - - # compare generaldata.ini - actual_path = study_assets.study_dir.joinpath("settings/generaldata.ini") - actual = IniReader().read(actual_path) - expected_path = study_assets.expected_dir.joinpath("settings/generaldata.ini") - expected = IniReader().read(expected_path) - assert actual == expected diff --git a/tests/storage/study_upgrader/test_upgrade_720.py b/tests/storage/study_upgrader/test_upgrade_720.py deleted file mode 100644 index 61f6cea7ea..0000000000 --- a/tests/storage/study_upgrader/test_upgrade_720.py +++ /dev/null @@ -1,28 +0,0 @@ -# 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 antarest.study.storage.study_upgrader import StudyUpgrader -from tests.storage.business.test_study_version_upgrader import are_same_dir -from tests.storage.study_upgrader.conftest import StudyAssets - - -def test_nominal_case(study_assets: StudyAssets): - """ - Check that `settings/generaldata.ini` is upgraded to version 720. - """ - - # upgrade the study - study_upgrader = StudyUpgrader(study_assets.study_dir, "720") - study_upgrader.upgrade() - - # compare folder - assert are_same_dir(study_assets.study_dir, study_assets.expected_dir, ignore=["study.antares"]) diff --git a/tests/storage/study_upgrader/test_upgrade_800.py b/tests/storage/study_upgrader/test_upgrade_800.py deleted file mode 100644 index d03f483502..0000000000 --- a/tests/storage/study_upgrader/test_upgrade_800.py +++ /dev/null @@ -1,32 +0,0 @@ -# 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 antarest.study.storage.rawstudy.ini_reader import IniReader -from antarest.study.storage.study_upgrader import StudyUpgrader -from tests.storage.study_upgrader.conftest import StudyAssets - - -def test_nominal_case(study_assets: StudyAssets): - """ - Check that `settings/generaldata.ini` is upgraded to version 800. - """ - - # upgrade the study - study_upgrader = StudyUpgrader(study_assets.study_dir, "800") - study_upgrader.upgrade() - - # compare generaldata.ini - actual_path = study_assets.study_dir.joinpath("settings/generaldata.ini") - actual = IniReader().read(actual_path) - expected_path = study_assets.expected_dir.joinpath("settings/generaldata.ini") - expected = IniReader().read(expected_path) - assert actual == expected diff --git a/tests/storage/study_upgrader/test_upgrade_810.py b/tests/storage/study_upgrader/test_upgrade_810.py deleted file mode 100644 index 9ba51de57f..0000000000 --- a/tests/storage/study_upgrader/test_upgrade_810.py +++ /dev/null @@ -1,39 +0,0 @@ -# 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 antarest.study.storage.rawstudy.ini_reader import IniReader -from antarest.study.storage.study_upgrader import StudyUpgrader -from tests.storage.business.test_study_version_upgrader import are_same_dir -from tests.storage.study_upgrader.conftest import StudyAssets - - -def test_nominal_case(study_assets: StudyAssets): - """ - Check that `settings/generaldata.ini` is upgraded to version 810. - """ - - # upgrade the study - study_upgrader = StudyUpgrader(study_assets.study_dir, "810") - study_upgrader.upgrade() - - # compare generaldata.ini - actual_path = study_assets.study_dir.joinpath("settings/generaldata.ini") - actual = IniReader().read(actual_path) - expected_path = study_assets.expected_dir.joinpath("settings/generaldata.ini") - expected = IniReader().read(expected_path) - assert actual == expected - - # compare folders (because the upgrade should create empty "renewables" folder) - assert are_same_dir( - study_assets.study_dir.joinpath("input"), - study_assets.expected_dir.joinpath("input"), - ) diff --git a/tests/storage/study_upgrader/test_upgrade_820.py b/tests/storage/study_upgrader/test_upgrade_820.py deleted file mode 100644 index 41cf4198d3..0000000000 --- a/tests/storage/study_upgrader/test_upgrade_820.py +++ /dev/null @@ -1,38 +0,0 @@ -# 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 antarest.study.storage.rawstudy.ini_reader import IniReader -from antarest.study.storage.study_upgrader import StudyUpgrader -from tests.storage.business.test_study_version_upgrader import are_same_dir -from tests.storage.study_upgrader.conftest import StudyAssets - - -def test_nominal_case(study_assets: StudyAssets): - """ - Check that `settings/generaldata.ini` is upgraded to version 820. - """ - - # upgrade the study - study_upgrader = StudyUpgrader(study_assets.study_dir, "820") - study_upgrader.upgrade() - - # compare generaldata.ini - actual_path = study_assets.study_dir.joinpath("settings/generaldata.ini") - actual = IniReader().read(actual_path) - expected_path = study_assets.expected_dir.joinpath("settings/generaldata.ini") - expected = IniReader().read(expected_path) - assert actual == expected - - # compare links - actual_link_path = study_assets.study_dir.joinpath("input/links") - expected_link_path = study_assets.expected_dir.joinpath("input/links") - assert are_same_dir(actual_link_path, expected_link_path) diff --git a/tests/storage/study_upgrader/test_upgrade_830.py b/tests/storage/study_upgrader/test_upgrade_830.py deleted file mode 100644 index 146029f17e..0000000000 --- a/tests/storage/study_upgrader/test_upgrade_830.py +++ /dev/null @@ -1,38 +0,0 @@ -# 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 antarest.study.storage.rawstudy.ini_reader import IniReader -from antarest.study.storage.study_upgrader import StudyUpgrader -from tests.storage.business.test_study_version_upgrader import are_same_dir -from tests.storage.study_upgrader.conftest import StudyAssets - - -def test_nominal_case(study_assets: StudyAssets): - """ - Check that `settings/generaldata.ini` is upgraded to version 830. - """ - - # upgrade the study - study_upgrader = StudyUpgrader(study_assets.study_dir, "830") - study_upgrader.upgrade() - - # compare generaldata.ini - actual_path = study_assets.study_dir.joinpath("settings/generaldata.ini") - actual = IniReader().read(actual_path) - expected_path = study_assets.expected_dir.joinpath("settings/generaldata.ini") - expected = IniReader().read(expected_path) - assert actual == expected - - # compare areas - actual_area_path = study_assets.study_dir.joinpath("input/areas") - expected_area_path = study_assets.expected_dir.joinpath("input/areas") - assert are_same_dir(actual_area_path, expected_area_path) diff --git a/tests/storage/study_upgrader/test_upgrade_840.py b/tests/storage/study_upgrader/test_upgrade_840.py deleted file mode 100644 index b5b99ddae5..0000000000 --- a/tests/storage/study_upgrader/test_upgrade_840.py +++ /dev/null @@ -1,32 +0,0 @@ -# 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 antarest.study.storage.rawstudy.ini_reader import IniReader -from antarest.study.storage.study_upgrader import StudyUpgrader -from tests.storage.study_upgrader.conftest import StudyAssets - - -def test_nominal_case(study_assets: StudyAssets): - """ - Check that `settings/generaldata.ini` is upgraded to version 840. - """ - - # upgrade the study - study_upgrader = StudyUpgrader(study_assets.study_dir, "840") - study_upgrader.upgrade() - - # compare generaldata.ini - actual_path = study_assets.study_dir.joinpath("settings/generaldata.ini") - actual = IniReader().read(actual_path) - expected_path = study_assets.expected_dir.joinpath("settings/generaldata.ini") - expected = IniReader().read(expected_path) - assert actual == expected diff --git a/tests/storage/study_upgrader/test_upgrade_850.py b/tests/storage/study_upgrader/test_upgrade_850.py deleted file mode 100644 index c4c040b5cb..0000000000 --- a/tests/storage/study_upgrader/test_upgrade_850.py +++ /dev/null @@ -1,33 +0,0 @@ -# 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 antarest.study.storage.rawstudy.ini_reader import IniReader -from antarest.study.storage.study_upgrader import StudyUpgrader -from tests.storage.study_upgrader.conftest import StudyAssets - - -# noinspection SpellCheckingInspection -def test_nominal_case(study_assets: StudyAssets): - """ - Check that `settings/generaldata.ini` is upgraded to version 850. - """ - - # upgrade the study - study_upgrader = StudyUpgrader(study_assets.study_dir, "850") - study_upgrader.upgrade() - - # compare generaldata.ini - actual_path = study_assets.study_dir.joinpath("settings/generaldata.ini") - actual = IniReader().read(actual_path) - expected_path = study_assets.expected_dir.joinpath("settings/generaldata.ini") - expected = IniReader().read(expected_path) - assert actual == expected diff --git a/tests/storage/study_upgrader/test_upgrade_860.py b/tests/storage/study_upgrader/test_upgrade_860.py deleted file mode 100644 index 704c4aaf44..0000000000 --- a/tests/storage/study_upgrader/test_upgrade_860.py +++ /dev/null @@ -1,30 +0,0 @@ -# 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 antarest.study.storage.study_upgrader import StudyUpgrader -from tests.storage.business.test_study_version_upgrader import are_same_dir -from tests.storage.study_upgrader.conftest import StudyAssets - - -def test_nominal_case(study_assets: StudyAssets): - """ - Check that 'st-storage' folder is created and filled. - """ - - # upgrade the study - study_upgrader = StudyUpgrader(study_assets.study_dir, "860") - study_upgrader.upgrade() - - # compare input folder - actual_input_path = study_assets.study_dir.joinpath("input") - expected_input_path = study_assets.expected_dir.joinpath("input") - assert are_same_dir(actual_input_path, expected_input_path) diff --git a/tests/storage/study_upgrader/test_upgrade_870.py b/tests/storage/study_upgrader/test_upgrade_870.py deleted file mode 100644 index f4fb6721b6..0000000000 --- a/tests/storage/study_upgrader/test_upgrade_870.py +++ /dev/null @@ -1,45 +0,0 @@ -# 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 antarest.study.storage.study_upgrader import StudyUpgrader -from tests.storage.business.test_study_version_upgrader import are_same_dir -from tests.storage.study_upgrader.conftest import StudyAssets - - -def test_nominal_case(study_assets: StudyAssets): - """ - Check that binding constraints and thermal folders are correctly modified - """ - - # upgrade the study - study_upgrader = StudyUpgrader(study_assets.study_dir, "870") - study_upgrader.upgrade() - - # compare input folders (bindings + thermals) - actual_input_path = study_assets.study_dir.joinpath("input") - expected_input_path = study_assets.expected_dir.joinpath("input") - assert are_same_dir(actual_input_path, expected_input_path) - - -def test_empty_binding_constraints(study_assets: StudyAssets): - """ - Check that binding constraints and thermal folders are correctly modified - """ - - # upgrade the study - study_upgrader = StudyUpgrader(study_assets.study_dir, "870") - study_upgrader.upgrade() - - # compare input folders (bindings + thermals) - actual_input_path = study_assets.study_dir.joinpath("input") - expected_input_path = study_assets.expected_dir.joinpath("input") - assert are_same_dir(actual_input_path, expected_input_path) diff --git a/tests/storage/study_upgrader/test_upgrade_880.py b/tests/storage/study_upgrader/test_upgrade_880.py deleted file mode 100644 index 465092c4a8..0000000000 --- a/tests/storage/study_upgrader/test_upgrade_880.py +++ /dev/null @@ -1,30 +0,0 @@ -# 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 antarest.study.storage.study_upgrader import StudyUpgrader -from tests.storage.business.test_study_version_upgrader import are_same_dir -from tests.storage.study_upgrader.conftest import StudyAssets - - -def test_nominal_case(study_assets: StudyAssets): - """ - Check that short term storages are correctly modified - """ - - # upgrade the study - study_upgrader = StudyUpgrader(study_assets.study_dir, "880") - study_upgrader.upgrade() - - # compare st-storage folders (st-storage) - actual_input_path = study_assets.study_dir / "input" / "st-storage" - expected_input_path = study_assets.expected_dir / "input" / "st-storage" - assert are_same_dir(actual_input_path, expected_input_path) diff --git a/tests/storage/study_upgrader/upgrade_710/nominal_case/empty_study_700.expected.zip b/tests/storage/study_upgrader/upgrade_710/nominal_case/empty_study_700.expected.zip deleted file mode 100644 index 6ee11415f4..0000000000 Binary files a/tests/storage/study_upgrader/upgrade_710/nominal_case/empty_study_700.expected.zip and /dev/null differ diff --git a/tests/storage/study_upgrader/upgrade_710/nominal_case/empty_study_700.zip b/tests/storage/study_upgrader/upgrade_710/nominal_case/empty_study_700.zip deleted file mode 100644 index 483bbcb1db..0000000000 Binary files a/tests/storage/study_upgrader/upgrade_710/nominal_case/empty_study_700.zip and /dev/null differ diff --git a/tests/storage/study_upgrader/upgrade_720/nominal_case/empty_study_710.expected.zip b/tests/storage/study_upgrader/upgrade_720/nominal_case/empty_study_710.expected.zip deleted file mode 100644 index 6ee11415f4..0000000000 Binary files a/tests/storage/study_upgrader/upgrade_720/nominal_case/empty_study_710.expected.zip and /dev/null differ diff --git a/tests/storage/study_upgrader/upgrade_720/nominal_case/empty_study_710.zip b/tests/storage/study_upgrader/upgrade_720/nominal_case/empty_study_710.zip deleted file mode 100644 index 6ee11415f4..0000000000 Binary files a/tests/storage/study_upgrader/upgrade_720/nominal_case/empty_study_710.zip and /dev/null differ diff --git a/tests/storage/study_upgrader/upgrade_800/nominal_case/empty_study_720.expected.zip b/tests/storage/study_upgrader/upgrade_800/nominal_case/empty_study_720.expected.zip deleted file mode 100644 index 507d8a97f3..0000000000 Binary files a/tests/storage/study_upgrader/upgrade_800/nominal_case/empty_study_720.expected.zip and /dev/null differ diff --git a/tests/storage/study_upgrader/upgrade_810/nominal_case/empty_study_800.expected.zip b/tests/storage/study_upgrader/upgrade_810/nominal_case/empty_study_800.expected.zip deleted file mode 100644 index 4b5f52b66f..0000000000 Binary files a/tests/storage/study_upgrader/upgrade_810/nominal_case/empty_study_800.expected.zip and /dev/null differ diff --git a/tests/storage/study_upgrader/upgrade_810/nominal_case/empty_study_800.zip b/tests/storage/study_upgrader/upgrade_810/nominal_case/empty_study_800.zip deleted file mode 100644 index 507d8a97f3..0000000000 Binary files a/tests/storage/study_upgrader/upgrade_810/nominal_case/empty_study_800.zip and /dev/null differ diff --git a/tests/storage/study_upgrader/upgrade_820/nominal_case/little_study_810.expected.zip b/tests/storage/study_upgrader/upgrade_820/nominal_case/little_study_810.expected.zip deleted file mode 100644 index b1aade240b..0000000000 Binary files a/tests/storage/study_upgrader/upgrade_820/nominal_case/little_study_810.expected.zip and /dev/null differ diff --git a/tests/storage/study_upgrader/upgrade_820/nominal_case/little_study_810.zip b/tests/storage/study_upgrader/upgrade_820/nominal_case/little_study_810.zip deleted file mode 100644 index 3c0642d416..0000000000 Binary files a/tests/storage/study_upgrader/upgrade_820/nominal_case/little_study_810.zip and /dev/null differ diff --git a/tests/storage/study_upgrader/upgrade_830/nominal_case/little_study_820.expected.zip b/tests/storage/study_upgrader/upgrade_830/nominal_case/little_study_820.expected.zip deleted file mode 100644 index 17a885d7a5..0000000000 Binary files a/tests/storage/study_upgrader/upgrade_830/nominal_case/little_study_820.expected.zip and /dev/null differ diff --git a/tests/storage/study_upgrader/upgrade_830/nominal_case/little_study_820.zip b/tests/storage/study_upgrader/upgrade_830/nominal_case/little_study_820.zip deleted file mode 100644 index 007b06e663..0000000000 Binary files a/tests/storage/study_upgrader/upgrade_830/nominal_case/little_study_820.zip and /dev/null differ diff --git a/tests/storage/study_upgrader/upgrade_840/nominal_case/empty_study_830.expected.zip b/tests/storage/study_upgrader/upgrade_840/nominal_case/empty_study_830.expected.zip deleted file mode 100644 index b1e47107e1..0000000000 Binary files a/tests/storage/study_upgrader/upgrade_840/nominal_case/empty_study_830.expected.zip and /dev/null differ diff --git a/tests/storage/study_upgrader/upgrade_840/nominal_case/empty_study_830.zip b/tests/storage/study_upgrader/upgrade_840/nominal_case/empty_study_830.zip deleted file mode 100644 index ecced32a77..0000000000 Binary files a/tests/storage/study_upgrader/upgrade_840/nominal_case/empty_study_830.zip and /dev/null differ diff --git a/tests/storage/study_upgrader/upgrade_850/nominal_case/empty_study_840.expected.zip b/tests/storage/study_upgrader/upgrade_850/nominal_case/empty_study_840.expected.zip deleted file mode 100644 index a402011e16..0000000000 Binary files a/tests/storage/study_upgrader/upgrade_850/nominal_case/empty_study_840.expected.zip and /dev/null differ diff --git a/tests/storage/study_upgrader/upgrade_850/nominal_case/empty_study_840.zip b/tests/storage/study_upgrader/upgrade_850/nominal_case/empty_study_840.zip deleted file mode 100644 index c9e017d096..0000000000 Binary files a/tests/storage/study_upgrader/upgrade_850/nominal_case/empty_study_840.zip and /dev/null differ diff --git a/tests/storage/study_upgrader/upgrade_860/nominal_case/little_study_850.expected.zip b/tests/storage/study_upgrader/upgrade_860/nominal_case/little_study_850.expected.zip deleted file mode 100644 index 4cb3dc548d..0000000000 Binary files a/tests/storage/study_upgrader/upgrade_860/nominal_case/little_study_850.expected.zip and /dev/null differ diff --git a/tests/storage/study_upgrader/upgrade_860/nominal_case/little_study_850.zip b/tests/storage/study_upgrader/upgrade_860/nominal_case/little_study_850.zip deleted file mode 100644 index b53b6decd9..0000000000 Binary files a/tests/storage/study_upgrader/upgrade_860/nominal_case/little_study_850.zip and /dev/null differ diff --git a/tests/storage/study_upgrader/upgrade_870/empty_binding_constraints/little_study_860.expected.zip b/tests/storage/study_upgrader/upgrade_870/empty_binding_constraints/little_study_860.expected.zip deleted file mode 100644 index f78b95bcfe..0000000000 Binary files a/tests/storage/study_upgrader/upgrade_870/empty_binding_constraints/little_study_860.expected.zip and /dev/null differ diff --git a/tests/storage/study_upgrader/upgrade_870/empty_binding_constraints/little_study_860.zip b/tests/storage/study_upgrader/upgrade_870/empty_binding_constraints/little_study_860.zip deleted file mode 100644 index ecc496b084..0000000000 Binary files a/tests/storage/study_upgrader/upgrade_870/empty_binding_constraints/little_study_860.zip and /dev/null differ diff --git a/tests/storage/study_upgrader/upgrade_870/nominal_case/little_study_860.expected.zip b/tests/storage/study_upgrader/upgrade_870/nominal_case/little_study_860.expected.zip deleted file mode 100644 index bb83d77745..0000000000 Binary files a/tests/storage/study_upgrader/upgrade_870/nominal_case/little_study_860.expected.zip and /dev/null differ diff --git a/tests/storage/study_upgrader/upgrade_870/nominal_case/little_study_860.zip b/tests/storage/study_upgrader/upgrade_870/nominal_case/little_study_860.zip deleted file mode 100644 index ee4aef0d34..0000000000 Binary files a/tests/storage/study_upgrader/upgrade_870/nominal_case/little_study_860.zip and /dev/null differ diff --git a/tests/storage/study_upgrader/upgrade_880/nominal_case/little_study_870.expected.zip b/tests/storage/study_upgrader/upgrade_880/nominal_case/little_study_870.expected.zip deleted file mode 100644 index ddeb10ad18..0000000000 Binary files a/tests/storage/study_upgrader/upgrade_880/nominal_case/little_study_870.expected.zip and /dev/null differ diff --git a/tests/storage/study_upgrader/upgrade_880/nominal_case/little_study_870.zip b/tests/storage/study_upgrader/upgrade_880/nominal_case/little_study_870.zip deleted file mode 100644 index 88aa7533c3..0000000000 Binary files a/tests/storage/study_upgrader/upgrade_880/nominal_case/little_study_870.zip and /dev/null differ diff --git a/tests/study/business/areas/test_st_storage_management.py b/tests/study/business/areas/test_st_storage_management.py index 56a42d88a0..b0cef2108d 100644 --- a/tests/study/business/areas/test_st_storage_management.py +++ b/tests/study/business/areas/test_st_storage_management.py @@ -165,6 +165,7 @@ def test_get_all_storages__nominal_case( "efficiency": 0.94, "initialLevel": 0.5, "initialLevelOptim": True, + "efficiencyWithdrawal": None, }, { "id": "storage2", @@ -177,6 +178,7 @@ def test_get_all_storages__nominal_case( "efficiency": 0.78, "initialLevel": 0.5, "initialLevelOptim": False, + "efficiencyWithdrawal": None, }, { "id": "storage3", @@ -189,6 +191,7 @@ def test_get_all_storages__nominal_case( "efficiency": 0.72, "initialLevel": 1.0, "initialLevelOptim": False, + "efficiencyWithdrawal": None, }, ], } @@ -268,6 +271,7 @@ def test_get_st_storages__nominal_case( "reservoirCapacity": 20000.0, "withdrawalNominalCapacity": 1500.0, "enabled": None, + "efficiencyWithdrawal": None, }, { "efficiency": 0.78, @@ -280,6 +284,7 @@ def test_get_st_storages__nominal_case( "reservoirCapacity": 20000.0, "withdrawalNominalCapacity": 1500.0, "enabled": None, + "efficiencyWithdrawal": None, }, { "efficiency": 0.72, @@ -292,6 +297,7 @@ def test_get_st_storages__nominal_case( "reservoirCapacity": 21000.0, "withdrawalNominalCapacity": 1500.0, "enabled": None, + "efficiencyWithdrawal": None, }, ] assert actual == expected @@ -379,6 +385,7 @@ def test_get_st_storage__nominal_case( "reservoirCapacity": 20000.0, "withdrawalNominalCapacity": 1500.0, "enabled": None, + "efficiencyWithdrawal": None, } assert actual == expected diff --git a/tests/study/storage/rawstudy/test_raw_study_service.py b/tests/study/storage/rawstudy/test_raw_study_service.py index acf6557bd4..de3e82927a 100644 --- a/tests/study/storage/rawstudy/test_raw_study_service.py +++ b/tests/study/storage/rawstudy/test_raw_study_service.py @@ -25,7 +25,7 @@ from antarest.study.business.utils import execute_or_add_commands from antarest.study.model import RawStudy, StudyAdditionalData from antarest.study.storage.patch_service import PatchService -from antarest.study.storage.rawstudy.model.filesystem.config.st_storage import STStorageConfig, STStorageGroup +from antarest.study.storage.rawstudy.model.filesystem.config.st_storage import STStorageGroup from antarest.study.storage.rawstudy.raw_study_service import RawStudyService from antarest.study.storage.storage_service import StudyStorageService from antarest.study.storage.variantstudy.business.matrix_constants_generator import GeneratorMatrixConstants @@ -134,16 +134,16 @@ def test_export_study_flat( create_st_storage = CreateSTStorage( command_context=command_context, area_id="fr", - parameters=STStorageConfig( - id="", # will be calculated ;-) - name="Storage1", - group=STStorageGroup.BATTERY, - injection_nominal_capacity=1500, - withdrawal_nominal_capacity=1500, - reservoir_capacity=20000, - efficiency=0.94, - initial_level_optim=True, - ), + parameters={ + "id": "", + "name": "Storage1", + "group": STStorageGroup.BATTERY, + "injection_nominal_capacity": 1500, + "withdrawal_nominal_capacity": 1500, + "reservoir_capacity": 20000, + "efficiency": 0.94, + "initial_level_optim": True, + }, pmax_injection=pmax_injection.tolist(), inflows=inflows.tolist(), ) diff --git a/tests/study/storage/variantstudy/test_variant_study_service.py b/tests/study/storage/variantstudy/test_variant_study_service.py index cd8f9100c0..82aae2aac1 100644 --- a/tests/study/storage/variantstudy/test_variant_study_service.py +++ b/tests/study/storage/variantstudy/test_variant_study_service.py @@ -198,16 +198,16 @@ def test_generate_task( create_st_storage = CreateSTStorage( command_context=command_context, area_id="fr", - parameters=STStorageConfig( - id="", # will be calculated ;-) - name="Storage1", - group=STStorageGroup.BATTERY, - injection_nominal_capacity=1500, - withdrawal_nominal_capacity=1500, - reservoir_capacity=20000, - efficiency=0.94, - initial_level_optim=True, - ), + parameters={ + "id": "", # will be calculated ;-) + "name": "Storage1", + "group": STStorageGroup.BATTERY, + "injection_nominal_capacity": 1500, + "withdrawal_nominal_capacity": 1500, + "reservoir_capacity": 20000, + "efficiency": 0.94, + "initial_level_optim": True, + }, pmax_injection=pmax_injection.tolist(), inflows=inflows.tolist(), ) diff --git a/tests/variantstudy/model/command/test_create_st_storage.py b/tests/variantstudy/model/command/test_create_st_storage.py index 14fbef9b8b..9c49a306b3 100644 --- a/tests/variantstudy/model/command/test_create_st_storage.py +++ b/tests/variantstudy/model/command/test_create_st_storage.py @@ -9,7 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. - +import copy import re import numpy as np @@ -17,7 +17,6 @@ from pydantic import ValidationError from antarest.study.storage.rawstudy.model.filesystem.config.model import transform_name_to_id -from antarest.study.storage.rawstudy.model.filesystem.config.st_storage import STStorageConfig from antarest.study.storage.rawstudy.model.filesystem.factory import FileStudy from antarest.study.storage.study_upgrader import StudyUpgrader from antarest.study.storage.variantstudy.business.utils import strip_matrix_protocol @@ -82,7 +81,7 @@ def test_init(self, command_context: CommandContext): cmd = CreateSTStorage( command_context=command_context, area_id="area_fr", - parameters=STStorageConfig(**PARAMETERS), + parameters=PARAMETERS, pmax_injection=pmax_injection.tolist(), # type: ignore inflows=inflows.tolist(), # type: ignore ) @@ -92,8 +91,9 @@ def test_init(self, command_context: CommandContext): assert cmd.version == 1 assert cmd.command_context == command_context assert cmd.area_id == "area_fr" - expected_parameters = {k: str(v) for k, v in PARAMETERS.items()} - assert cmd.parameters == STStorageConfig(**expected_parameters) + expected_parameters = copy.deepcopy(PARAMETERS) + expected_parameters["id"] = "storage1" + assert cmd.parameters == expected_parameters # check the matrices links @@ -111,14 +111,14 @@ def test_init__invalid_storage_name(self, recent_study: FileStudy, command_conte CreateSTStorage( command_context=command_context, area_id="dummy", - parameters=STStorageConfig(**parameters), + parameters=parameters, ) # We get 2 errors because the `storage_name` is duplicated in the `parameters`: assert ctx.value.error_count() == 1 raised_error = ctx.value.errors()[0] assert raised_error["type"] == "value_error" assert raised_error["msg"] == "Value error, Invalid name '?%$$'." - assert raised_error["input"] == { + assert raised_error["input"]["parameters"] == { "efficiency": 0.94, "group": "Battery", "initialleveloptim": True, @@ -135,7 +135,7 @@ def test_init__invalid_matrix_values(self, command_context: CommandContext): CreateSTStorage( command_context=command_context, area_id="area_fr", - parameters=STStorageConfig(**PARAMETERS), + parameters=PARAMETERS, pmax_injection=array.tolist(), # type: ignore ) assert ctx.value.error_count() == 1 @@ -151,7 +151,7 @@ def test_init__invalid_matrix_shape(self, command_context: CommandContext): CreateSTStorage( command_context=command_context, area_id="area_fr", - parameters=STStorageConfig(**PARAMETERS), + parameters=PARAMETERS, pmax_injection=array.tolist(), # type: ignore ) assert ctx.value.error_count() == 1 @@ -167,7 +167,7 @@ def test_init__invalid_nan_value(self, command_context: CommandContext): CreateSTStorage( command_context=command_context, area_id="area_fr", - parameters=STStorageConfig(**PARAMETERS), + parameters=PARAMETERS, pmax_injection=array.tolist(), # type: ignore ) assert ctx.value.error_count() == 1 @@ -181,7 +181,7 @@ def test_init__invalid_matrix_type(self, command_context: CommandContext): CreateSTStorage( command_context=command_context, area_id="area_fr", - parameters=STStorageConfig(**PARAMETERS), + parameters=PARAMETERS, pmax_injection=[1, 2, 3], ) assert ctx.value.error_count() == 1 @@ -196,7 +196,7 @@ def test_apply_config__invalid_version(self, empty_study: FileStudy, command_con create_st_storage = CreateSTStorage( command_context=command_context, area_id="foo", - parameters=STStorageConfig(**PARAMETERS), + parameters=PARAMETERS, ) command_output = create_st_storage.apply_config(empty_study.config) @@ -214,7 +214,7 @@ def test_apply_config__missing_area(self, recent_study: FileStudy, command_conte create_st_storage = CreateSTStorage( command_context=command_context, area_id="unknown area", # bad ID - parameters=STStorageConfig(**PARAMETERS), + parameters=PARAMETERS, ) command_output = create_st_storage.apply_config(recent_study.config) @@ -238,7 +238,7 @@ def test_apply_config__duplicate_storage(self, recent_study: FileStudy, command_ create_st_storage = CreateSTStorage( command_context=command_context, area_id=transform_name_to_id(create_area.area_name), - parameters=STStorageConfig(**PARAMETERS), + parameters=PARAMETERS, ) command_output = create_st_storage.apply_config(recent_study.config) assert command_output.status is True @@ -248,7 +248,7 @@ def test_apply_config__duplicate_storage(self, recent_study: FileStudy, command_ create_st_storage = CreateSTStorage( command_context=command_context, area_id=transform_name_to_id(create_area.area_name), - parameters=STStorageConfig(**parameters), + parameters=parameters, ) command_output = create_st_storage.apply_config(recent_study.config) @@ -272,7 +272,7 @@ def test_apply_config__nominal_case(self, recent_study: FileStudy, command_conte create_st_storage = CreateSTStorage( command_context=command_context, area_id=transform_name_to_id(create_area.area_name), - parameters=STStorageConfig(**PARAMETERS), + parameters=PARAMETERS, ) command_output = create_st_storage.apply_config(recent_study.config) @@ -299,7 +299,7 @@ def test_apply__nominal_case(self, recent_study: FileStudy, command_context: Com cmd = CreateSTStorage( command_context=command_context, area_id=transform_name_to_id(create_area.area_name), - parameters=STStorageConfig(**PARAMETERS), + parameters=PARAMETERS, pmax_injection=pmax_injection.tolist(), # type: ignore inflows=inflows.tolist(), # type: ignore ) @@ -348,7 +348,7 @@ def test_apply__invalid_apply_config(self, empty_study: FileStudy, command_conte cmd = CreateSTStorage( command_context=command_context, area_id=transform_name_to_id(create_area.area_name), - parameters=STStorageConfig(**PARAMETERS), + parameters=PARAMETERS, ) command_output = cmd.apply(empty_study) assert not command_output.status # invalid study (too old) @@ -358,21 +358,17 @@ def test_to_dto(self, command_context: CommandContext): cmd = CreateSTStorage( command_context=command_context, area_id="area_fr", - parameters=STStorageConfig(**PARAMETERS), + parameters=PARAMETERS, ) actual = cmd.to_dto() - expected_parameters = PARAMETERS.copy() - # `initiallevel` = 0.5 (the default value) because `initialleveloptim` is True - expected_parameters["initiallevel"] = 0.5 constants = command_context.generator_matrix_constants - assert actual == CommandDTO( action=CommandName.CREATE_ST_STORAGE.value, args={ "area_id": "area_fr", - "parameters": expected_parameters, + "parameters": PARAMETERS, "pmax_injection": strip_matrix_protocol(constants.get_st_storage_pmax_withdrawal()), "pmax_withdrawal": strip_matrix_protocol(constants.get_st_storage_pmax_withdrawal()), "lower_rule_curve": strip_matrix_protocol(constants.get_st_storage_lower_rule_curve()), @@ -385,7 +381,7 @@ def test_match_signature(self, command_context: CommandContext): cmd = CreateSTStorage( command_context=command_context, area_id="area_fr", - parameters=STStorageConfig(**PARAMETERS), + parameters=PARAMETERS, ) assert cmd.match_signature() == "create_st_storage%area_fr%storage1" @@ -400,12 +396,12 @@ def test_match( cmd1 = CreateSTStorage( command_context=command_context, area_id="area_fr", - parameters=STStorageConfig(**PARAMETERS), + parameters=PARAMETERS, ) cmd2 = CreateSTStorage( command_context=command_context, area_id=area_id, - parameters=STStorageConfig(**parameters), + parameters=parameters, ) light_equal = area_id == cmd1.area_id and parameters["name"] == cmd1.storage_name assert cmd1.match(cmd2, equal=False) == light_equal @@ -416,7 +412,7 @@ def test_match__unknown_type(self, command_context: CommandContext): cmd1 = CreateSTStorage( command_context=command_context, area_id="area_fr", - parameters=STStorageConfig(**PARAMETERS), + parameters=PARAMETERS, ) # Always `False` when compared to another object type assert cmd1.match(..., equal=False) is False @@ -426,14 +422,14 @@ def test_create_diff__not_equals(self, command_context: CommandContext): cmd = CreateSTStorage( command_context=command_context, area_id="area_fr", - parameters=STStorageConfig(**PARAMETERS), + parameters=PARAMETERS, ) upper_rule_curve = GEN.random((8760, 1)) inflows = GEN.uniform(0, 1000, size=(8760, 1)) other = CreateSTStorage( command_context=command_context, area_id=cmd.area_id, - parameters=STStorageConfig(**OTHER_PARAMETERS), + parameters=OTHER_PARAMETERS, upper_rule_curve=upper_rule_curve.tolist(), # type: ignore inflows=inflows.tolist(), # type: ignore ) @@ -461,7 +457,7 @@ def test_create_diff__equals(self, command_context: CommandContext): cmd = CreateSTStorage( command_context=command_context, area_id="area_fr", - parameters=STStorageConfig(**PARAMETERS), + parameters=PARAMETERS, ) actual = cmd.create_diff(cmd) assert not actual @@ -470,7 +466,7 @@ def test_get_inner_matrices(self, command_context: CommandContext): cmd = CreateSTStorage( command_context=command_context, area_id="area_fr", - parameters=STStorageConfig(**PARAMETERS), + parameters=PARAMETERS, ) actual = cmd.get_inner_matrices() constants = command_context.generator_matrix_constants diff --git a/webapp/src/components/App/Singlestudy/explore/Configuration/General/dialogs/ThematicTrimmingDialog/utils.ts b/webapp/src/components/App/Singlestudy/explore/Configuration/General/dialogs/ThematicTrimmingDialog/utils.ts index a3a16e5661..eda7efe31e 100644 --- a/webapp/src/components/App/Singlestudy/explore/Configuration/General/dialogs/ThematicTrimmingDialog/utils.ts +++ b/webapp/src/components/App/Singlestudy/explore/Configuration/General/dialogs/ThematicTrimmingDialog/utils.ts @@ -102,6 +102,7 @@ const fieldLabelsByGroup: Record< stsInjByPlant: "STS INJ BY PLANT", stsLvlByPlant: "STS LVL BY PLANT", stsWithdrawalByPlant: "STS WITHDRAWAL BY PLANT", + stsByGroup: "STS BY GROUP", }, generationThermals: { avlDtg: "AVL DTG", diff --git a/webapp/src/services/api/studies/config/thematicTrimming/types.ts b/webapp/src/services/api/studies/config/thematicTrimming/types.ts index 4edbc2075f..27df6d7847 100644 --- a/webapp/src/services/api/studies/config/thematicTrimming/types.ts +++ b/webapp/src/services/api/studies/config/thematicTrimming/types.ts @@ -113,6 +113,8 @@ export interface ThematicTrimmingConfig { other5Level?: boolean; // Since v8.8 stsCashflowByCluster?: boolean; + // Since v9.1 + stsByGroup?: boolean; } export interface GetThematicTrimmingConfigParams {