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

feat(ts-gen): add links ts-generation info inside DB #2302

Open
wants to merge 55 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
2940d4b
add alembic migration
MartinBelthle Jan 20, 2025
93fc3f7
add table models
MartinBelthle Jan 20, 2025
5442ada
always build data on the fly
MartinBelthle Jan 20, 2025
99d66f5
rename tables
MartinBelthle Jan 21, 2025
f66a84e
continue work
MartinBelthle Jan 21, 2025
8cd95f6
make matrices nullable inside DB
MartinBelthle Jan 21, 2025
feaaaec
fix typo inside db query
MartinBelthle Jan 21, 2025
351a342
fix remove link code
MartinBelthle Jan 21, 2025
e432b5d
fix test
MartinBelthle Jan 21, 2025
c114345
update downgrade alembic
MartinBelthle Jan 21, 2025
2ffa87a
introduce new class
MartinBelthle Jan 21, 2025
5ada079
implement create link method
MartinBelthle Jan 21, 2025
3ec33dd
update link implemented
MartinBelthle Jan 21, 2025
535e84c
fix one test
MartinBelthle Jan 21, 2025
431fba3
30 test don't pass
MartinBelthle Jan 21, 2025
19b085b
fix update link code
MartinBelthle Jan 21, 2025
9b2911f
clears DB when snapshot is deleted
MartinBelthle Jan 21, 2025
c3a286f
fix table mode test
MartinBelthle Jan 21, 2025
b8f5042
try to fix test
MartinBelthle Jan 21, 2025
2255174
fix one test
MartinBelthle Jan 21, 2025
22291c3
fix some tests
MartinBelthle Jan 21, 2025
44ec0f9
fix link creation test
MartinBelthle Jan 21, 2025
d6ef6ea
fix table mode test
MartinBelthle Jan 22, 2025
71c7807
fix one test
MartinBelthle Jan 22, 2025
fb48a8e
fix test
MartinBelthle Jan 22, 2025
e2a09b2
fix last test failing
MartinBelthle Jan 22, 2025
cf9a18e
fix last test
MartinBelthle Jan 22, 2025
c76481c
add if condition inside update link
MartinBelthle Jan 22, 2025
27dd4f7
handle the update link well
MartinBelthle Jan 22, 2025
357a6b4
add comment
MartinBelthle Jan 22, 2025
ea70fa2
adapt get method
MartinBelthle Jan 22, 2025
e9dd22e
continue wokr
MartinBelthle Jan 22, 2025
95dba05
finalize work on getters
MartinBelthle Jan 22, 2025
816ad25
try to fix failing tests
MartinBelthle Jan 22, 2025
f142ae5
add unit test for link creation
MartinBelthle Jan 22, 2025
fca9133
start adding some tests
MartinBelthle Jan 22, 2025
4d97eba
continue test for update link
MartinBelthle Jan 22, 2025
1caf500
add todo
MartinBelthle Jan 22, 2025
a4209a4
add test for remove link command
MartinBelthle Jan 22, 2025
00e399f
add tests for db cleaning with snapshot
MartinBelthle Jan 22, 2025
f3c8c64
remove unused imports
MartinBelthle Jan 22, 2025
afe3bb5
fix code to make the test pass
MartinBelthle Jan 22, 2025
fda4f13
fix little issues
MartinBelthle Jan 22, 2025
ab2f3ce
fix test
MartinBelthle Jan 22, 2025
a17d521
simplify links testing
MartinBelthle Jan 27, 2025
14b175a
add a test that fails for now
MartinBelthle Jan 27, 2025
abb4349
fix code
MartinBelthle Jan 27, 2025
07ac311
clear db when invalidating the cache
MartinBelthle Jan 28, 2025
d504f51
put the DB copy inside the snapshot generation
MartinBelthle Jan 28, 2025
a394dce
fix test with new behavior
MartinBelthle Jan 28, 2025
4a1e5b8
add index for study_id inside DB
MartinBelthle Jan 28, 2025
20d2f82
add tricky test
MartinBelthle Jan 28, 2025
e5d9996
merge with dev
MartinBelthle Feb 6, 2025
f6dd05f
resolve conflicts with dev
MartinBelthle Feb 11, 2025
7eeef2d
fix import issue
MartinBelthle Feb 11, 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
59 changes: 59 additions & 0 deletions alembic/versions/dadad513f1b6_create_links_ts_generation_tables.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"""create_links_ts_generation_tables

Revision ID: dadad513f1b6
Revises: bae9c99bc42d
Create Date: 2025-01-20 10:11:01.293931

"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = 'dadad513f1b6'
down_revision = 'bae9c99bc42d'
branch_labels = None
depends_on = None


def upgrade():
op.create_table(
"nb_years_ts_generation",
sa.Column("id", sa.String(length=36), nullable=False),
sa.Column("links", sa.Integer(), server_default="1", nullable=False),
sa.ForeignKeyConstraint(
["id"],
["study.id"],
ondelete="CASCADE"
),
sa.PrimaryKeyConstraint("id"),
sa.Index('ix_nb_years_ts_generation_study_id', 'study_id')
)

default_boolean = sa.text('1') if op.get_context().dialect.name == 'sqlite' else 't'
op.create_table(
"links_parameters_ts_generation",
sa.Column("id", sa.Integer()),
sa.Column("area_from", sa.String(), nullable=False),
sa.Column("area_to", sa.String(), nullable=False),
sa.Column("prepro", sa.String(), nullable=True),
sa.Column("modulation", sa.String(), nullable=True),
sa.Column("unit_count", sa.Integer(), nullable=False, server_default="1"),
sa.Column("nominal_capacity", sa.Float(), nullable=False, server_default="0"),
sa.Column("law_planned", sa.Enum('uniform', 'geometric', name='lawplanned'), nullable=False),
sa.Column("law_forced", sa.Enum('uniform', 'geometric', name='lawforced'), nullable=False),
sa.Column("volatility_planned", sa.String(), nullable=False, server_default="0"),
sa.Column("volatility_forced", sa.String(), nullable=False, server_default="0"),
sa.Column("force_no_generation", sa.Boolean(), nullable=False, server_default=default_boolean),
sa.Column("study_id", sa.String(length=36), nullable=False),
sa.ForeignKeyConstraint(
MartinBelthle marked this conversation as resolved.
Show resolved Hide resolved
["study_id"],
["study.id"],
ondelete="CASCADE"
),
sa.PrimaryKeyConstraint("id")
)


def downgrade():
op.drop_table("nb_years_ts_generation")
op.drop_table("links_parameters_ts_generation")
39 changes: 37 additions & 2 deletions antarest/study/business/link_management.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@

from antarest.core.exceptions import LinkNotFound
from antarest.core.model import JSON
from antarest.study.business.model.link_model import LinkBaseDTO, LinkDTO, LinkInternal
from antarest.core.utils.fastapi_sqlalchemy import db
from antarest.study.business.model.link_model import LinkBaseDTO, LinkDTO, LinkInternal, LinkTsGeneration
from antarest.study.business.utils import execute_or_add_commands
from antarest.study.model import RawStudy, Study
from antarest.study.model import LinksParametersTsGeneration, RawStudy, Study
from antarest.study.storage.rawstudy.model.filesystem.factory import FileStudy
from antarest.study.storage.storage_service import StudyStorageService
from antarest.study.storage.variantstudy.model.command.create_link import CreateLink
Expand All @@ -34,13 +35,19 @@ def get_all_links(self, study: Study) -> List[LinkDTO]:
file_study = self.storage_service.get_storage(study).get_raw(study)
result: List[LinkDTO] = []

ts_generation_parameters = self.get_all_links_ts_generation_information(study.id)

for area_id, area in file_study.config.areas.items():
links_config = file_study.tree.get(["input", "links", area_id, "properties"])

for link in area.links:
link_tree_config: Dict[str, Any] = links_config[link]
link_tree_config.update({"area1": area_id, "area2": link})

if area_id in ts_generation_parameters and link in ts_generation_parameters[area_id]:
link_ts_generation = ts_generation_parameters[area_id][link]
link_tree_config.update(link_ts_generation.model_dump(mode="json"))

link_internal = LinkInternal.model_validate(link_tree_config)

result.append(link_internal.to_dto())
Expand All @@ -54,10 +61,38 @@ def get_link(self, study: RawStudy, link: LinkInternal) -> LinkInternal:

link_properties.update({"area1": link.area1, "area2": link.area2})

ts_generation_parameters = self.get_single_link_ts_generation_information(study.id, link.area1, link.area2)
link_properties.update(ts_generation_parameters.model_dump(mode="json"))

updated_link = LinkInternal.model_validate(link_properties)

return updated_link

@staticmethod
def get_all_links_ts_generation_information(study_id: str) -> dict[str, dict[str, LinkTsGeneration]]:
db_dictionnary: dict[str, dict[str, LinkTsGeneration]] = {}
with db():
all_links_parameters: list[LinksParametersTsGeneration] = (
db.session.query(LinksParametersTsGeneration).filter_by(study_id=study_id).all()
)
for link_parameters in all_links_parameters:
area_from = link_parameters.area_from
area_to = link_parameters.area_to
db_dictionnary.setdefault(area_from, {})[area_to] = LinkTsGeneration.from_db_model(link_parameters)
return db_dictionnary

@staticmethod
def get_single_link_ts_generation_information(study_id: str, area_from: str, area_to: str) -> LinkTsGeneration:
with db():
links_parameters = (
db.session.query(LinksParametersTsGeneration)
.filter_by(study_id=study_id, area_from=area_from, area_to=area_to)
.first()
)
if links_parameters:
return LinkTsGeneration.from_db_model(links_parameters)
return LinkTsGeneration()

def create_link(self, study: Study, link_creation_dto: LinkDTO) -> LinkDTO:
link = link_creation_dto.to_internal(StudyVersion.parse(study.version))

Expand Down
59 changes: 56 additions & 3 deletions antarest/study/business/model/link_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
from antarest.core.serde import AntaresBaseModel
from antarest.core.utils.string import to_camel_case, to_kebab_case
from antarest.study.business.enum_ignore_case import EnumIgnoreCase
from antarest.study.model import STUDY_VERSION_8_2
from antarest.study.model import STUDY_VERSION_8_2, LinksParametersTsGeneration
from antarest.study.storage.rawstudy.model.filesystem.config.thermal import LawOption


class AssetType(EnumIgnoreCase):
Expand Down Expand Up @@ -139,7 +140,7 @@ def join_with_comma(values: List[FilterOption]) -> str:
]


class LinkBaseDTO(AntaresBaseModel):
class LinkIniDTO(AntaresBaseModel):
model_config = ConfigDict(alias_generator=to_camel_case, populate_by_name=True, extra="forbid")

hurdles_cost: bool = False
Expand All @@ -158,6 +159,49 @@ class LinkBaseDTO(AntaresBaseModel):
filter_year_by_year: Optional[comma_separated_enum_list] = field(default_factory=lambda: FILTER_VALUES)


class LinkTsGeneration(AntaresBaseModel):
model_config = ConfigDict(alias_generator=to_camel_case, populate_by_name=True, extra="forbid")

unit_count: int = 1
nominal_capacity: float = 0
law_planned: LawOption = LawOption.UNIFORM
law_forced: LawOption = LawOption.UNIFORM
volatility_planned: float = Field(default=0.0, ge=0, le=1)
volatility_forced: float = Field(default=0.0, ge=0, le=1)
force_no_generation: bool = True

@staticmethod
def from_db_model(links_parameters_db: LinksParametersTsGeneration) -> "LinkTsGeneration":
args = {
"unit_count": links_parameters_db.unit_count,
"nominal_capacity": links_parameters_db.nominal_capacity,
"law_planned": links_parameters_db.law_planned,
"law_forced": links_parameters_db.law_forced,
"volatility_planned": links_parameters_db.volatility_planned,
"volatility_forced": links_parameters_db.volatility_forced,
"force_no_generation": links_parameters_db.force_no_generation,
}
return LinkTsGeneration.model_validate(args)

def to_db_model(self, study_id: str, area_from: str, area_to: str) -> LinksParametersTsGeneration:
return LinksParametersTsGeneration(
study_id=study_id,
area_from=area_from,
area_to=area_to,
unit_count=self.unit_count,
nominal_capacity=self.nominal_capacity,
law_planned=self.law_planned,
law_forced=self.law_forced,
volatility_planned=self.volatility_planned,
volatility_forced=self.volatility_forced,
force_no_generation=self.force_no_generation,
)


class LinkBaseDTO(LinkIniDTO, LinkTsGeneration):
pass


class Area(AntaresBaseModel):
area1: str
area2: str
Expand All @@ -177,7 +221,7 @@ def to_internal(self, version: StudyVersion) -> "LinkInternal":
if version < STUDY_VERSION_8_2 and {"filter_synthesis", "filter_year_by_year"} & self.model_fields_set:
raise LinkValidationError("Cannot specify a filter value for study's version earlier than v8.2")

data = self.model_dump()
data = self.model_dump(mode="json")

if version < STUDY_VERSION_8_2:
data["filter_synthesis"] = None
Expand Down Expand Up @@ -206,6 +250,15 @@ class LinkInternal(AntaresBaseModel):
filter_synthesis: Optional[comma_separated_enum_list] = field(default_factory=lambda: FILTER_VALUES)
filter_year_by_year: Optional[comma_separated_enum_list] = field(default_factory=lambda: FILTER_VALUES)

# Ts-generation part
unit_count: int = 1
nominal_capacity: float = 0
law_planned: LawOption = LawOption.UNIFORM
law_forced: LawOption = LawOption.UNIFORM
volatility_planned: float = Field(default=0.0, ge=0, le=1)
volatility_forced: float = Field(default=0.0, ge=0, le=1)
force_no_generation: bool = True

def to_dto(self) -> LinkDTO:
data = self.model_dump()
return LinkDTO(**data)
39 changes: 39 additions & 0 deletions antarest/study/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
Column,
DateTime,
Enum,
Float,
ForeignKey,
Integer,
PrimaryKeyConstraint,
Expand All @@ -40,6 +41,7 @@
from antarest.core.serde import AntaresBaseModel
from antarest.login.model import Group, GroupDTO, Identity
from antarest.study.css4_colors import COLOR_NAMES
from antarest.study.storage.rawstudy.model.filesystem.config.thermal import LawOption

if TYPE_CHECKING:
# avoid circular import
Expand Down Expand Up @@ -90,6 +92,43 @@
}


class NbYearsTsGeneration(Base): # type:ignore
"""
A table to store how many columns needs to be generated by category and by study

Attributes:
id: A foreign key on the study ID.
links: An integer representing how many columns needs to be generated during links TS generation.
"""

__tablename__ = "nb_years_ts_generation"

id: str = Column(
String(36), ForeignKey("study.id", ondelete="CASCADE"), primary_key=True, index=True, nullable=False
)
links: int = Column(Integer, default=1, nullable=False)


class LinksParametersTsGeneration(Base): # type:ignore
"""A table to store for each link of a study, the input parameters to give to the TS generation algorithm"""

__tablename__ = "links_parameters_ts_generation"

id = Column(Integer, primary_key=True, unique=True)
study_id = Column(String(36), ForeignKey("study.id", ondelete="CASCADE"), index=True, nullable=False)
area_from = Column(String(255), nullable=False)
area_to = Column(String(255), nullable=False)
prepro = Column(String(255), nullable=True)
modulation = Column(String(255), nullable=True)
unit_count = Column(Integer, nullable=False, default=1)
nominal_capacity = Column(Float, nullable=False, default=0)
law_planned = Column(Enum(LawOption), default=LawOption.UNIFORM, nullable=False)
law_forced = Column(Enum(LawOption), default=LawOption.UNIFORM, nullable=False)
volatility_planned = Column(Float, nullable=False, default=0)
volatility_forced = Column(Float, nullable=False, default=0)
force_no_generation = Column(Boolean, nullable=False, default=True)


class StudyGroup(Base): # type:ignore
"""
A table to manage the many-to-many relationship between `Study` and `Group`
Expand Down
42 changes: 31 additions & 11 deletions antarest/study/storage/variantstudy/model/command/create_link.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@
from typing_extensions import override

from antarest.core.exceptions import LinkValidationError
from antarest.core.utils.fastapi_sqlalchemy import db
from antarest.core.utils.utils import assert_this
from antarest.matrixstore.model import MatrixData
from antarest.study.business.model.link_model import LinkInternal
from antarest.study.model import STUDY_VERSION_8_2
from antarest.study.business.model.link_model import Area, LinkInternal, LinkTsGeneration
from antarest.study.model import STUDY_VERSION_8_2, LinksParametersTsGeneration
from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig, Link
from antarest.study.storage.rawstudy.model.filesystem.factory import FileStudy
from antarest.study.storage.variantstudy.business.utils import strip_matrix_protocol, validate_matrix
Expand Down Expand Up @@ -216,19 +217,38 @@ def _apply(self, study_data: FileStudy, listener: Optional[ICommandListener] = N
if not output.status:
return output

to_exclude = {"area1", "area2"}
if version < STUDY_VERSION_8_2:
to_exclude.update("filter-synthesis", "filter-year-by-year")

validated_properties = LinkInternal.model_validate(self.parameters).model_dump(
by_alias=True, exclude=to_exclude
)

internal_link = LinkInternal.model_validate(self.parameters)
area_from = data["area_from"]
area_to = data["area_to"]

study_data.tree.save(validated_properties, ["input", "links", area_from, "properties", area_to])
# Saves ini properties
to_exclude = set(Area.model_fields.keys() | LinkTsGeneration.model_fields.keys())
if version < STUDY_VERSION_8_2:
to_exclude.update("filter-synthesis", "filter-year-by-year")
ini_properties = internal_link.model_dump(by_alias=True, exclude=to_exclude)
study_data.tree.save(ini_properties, ["input", "links", area_from, "properties", area_to])

# Saves DB properties
includes = set(LinkTsGeneration.model_fields.keys())
db_properties = LinkTsGeneration.model_validate(internal_link.model_dump(mode="json", include=includes))

with db():
new_parameters = LinksParametersTsGeneration(
study_id=study_data.config.study_id,
area_from=area_from,
area_to=area_to,
unit_count=db_properties.unit_count,
nominal_capacity=db_properties.nominal_capacity,
law_planned=db_properties.law_planned,
law_forced=db_properties.law_forced,
volatility_planned=db_properties.volatility_planned,
volatility_forced=db_properties.volatility_forced,
force_no_generation=db_properties.force_no_generation,
)
db.session.add(new_parameters)
db.session.commit()

# Saves matrices
self.series = self.series or (self.command_context.generator_matrix_constants.get_link(version=version))
self.direct = self.direct or (self.command_context.generator_matrix_constants.get_link_direct())
self.indirect = self.indirect or (self.command_context.generator_matrix_constants.get_link_indirect())
Expand Down
Loading
Loading