Skip to content

Commit

Permalink
consistency check between components and models added
Browse files Browse the repository at this point in the history
  • Loading branch information
vargastat committed Apr 4, 2024
1 parent 6d84cf1 commit e653f79
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 30 deletions.
13 changes: 9 additions & 4 deletions src/andromede/study/parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
from andromede.model.parsing import InputModel


def parse_yaml_components(input_components: typing.TextIO) -> "InputComponent":
def parse_yaml_components(input_components: typing.TextIO) -> "InputComponents":
tree = safe_load(input_components)
return InputComponent.model_validate(tree["study"])
return InputComponents.model_validate(tree["study"])


# Design note: actual parsing and validation is delegated to pydantic models
Expand All @@ -37,8 +37,13 @@ class InputPortConnections(BaseModel):


class InputComponent(BaseModel):
nodes: List[InputModel] = Field(default_factory=list)
components: List[InputModel] = Field(default_factory=list)
id: str
model: InputModel


class InputComponents(BaseModel):
nodes: List[InputComponent] = Field(default_factory=list)
components: List[InputComponent] = Field(default_factory=list)
connections: List[InputPortConnections] = Field(default_factory=list)

class Config:
Expand Down
26 changes: 22 additions & 4 deletions src/andromede/study/resolve_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,22 @@
# This file is part of the Antares project.
from typing import Dict, List, Optional

from andromede.model import Model
from andromede.model.library import Library
from andromede.model.parsing import InputModel
from andromede.model.resolve_library import _resolve_model_identifier
from andromede.study import Component, PortRef
from andromede.study.components import Components, components
from andromede.study.parsing import InputComponent, InputPortConnections
from andromede.study.parsing import InputComponents, InputPortConnections


def resolve_components_and_cnx(input_comp: InputComponent) -> Components:
def resolve_components_and_cnx(input_comp: InputComponents) -> Components:
"""
Resolves:
- components to be used for study
- connections between components"""
components_list = [_resolve_component(m, m.id) for m in input_comp.components]
components_list.extend(_resolve_component(n, n.id) for n in input_comp.nodes)
components_list = [_resolve_component(m.model, m.id) for m in input_comp.components]
components_list.extend(_resolve_component(n.model, n.id) for n in input_comp.nodes)
connections = {}

for cnx in input_comp.connections:
Expand Down Expand Up @@ -62,3 +64,19 @@ def _get_component_by_id(
) -> Optional[Component]:
components_dict = {component.id: component for component in components_list}
return components_dict.get(component_id)


def consistency_check(
input_components: Dict[str, Component], input_models: Dict[str, Model]
) -> bool:
"""
Checks if all components in the Components instances have a valid model from the library.
Returns True if all components are consistent, raises ValueError otherwis.
"""
model_ids_set = input_models.keys()
for component_id, component in input_components.items():
if component.model.id not in model_ids_set:
raise ValueError(
f"Error: Component {component_id} has invalid model ID: {component.model.id}"
)
return True
31 changes: 17 additions & 14 deletions tests/unittests/data/components.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,27 @@
study:
nodes:
- id: N
model: node
model:
id: node

components:
- id: G
model: generator
parameters:
- name: cost
type: constant
value: 100
- name: p_max
type: timeseries
timeseries: costs
model:
id: generator
parameters:
- name: cost
type: constant
value: 100
- name: p_max
type: timeseries
timeseries: costs
- id: D
model: demand
parameters:
- name: demand
type: constant
value: 1400
model:
id: demand
parameters:
- name: demand
type: constant
value: 1400

connections:
- id: cnx1
Expand Down
60 changes: 52 additions & 8 deletions tests/unittests/study/test_components_parsing.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,63 @@
from pathlib import Path

from andromede.study.parsing import parse_yaml_components
from andromede.study.resolve_components import resolve_components_and_cnx
import pytest

from andromede.model.parsing import InputLibrary, parse_yaml_library
from andromede.model.resolve_library import resolve_library
from andromede.study.parsing import (
InputComponent,
InputComponents,
parse_yaml_components,
)
from andromede.study.resolve_components import (
consistency_check,
resolve_components_and_cnx,
)

def test_parsing_components_ok(data_dir: Path):

@pytest.fixture
def input_component(
data_dir: Path,
) -> InputComponents:
compo_file = data_dir / "components.yml"

with compo_file.open() as c:
input_compo = parse_yaml_components(c)
assert len(input_compo.components) == 2
assert len(input_compo.nodes) == 1
assert len(input_compo.connections) == 2
return parse_yaml_components(c)


@pytest.fixture
def input_library(
data_dir: Path,
) -> InputLibrary:
library = data_dir / "lib.yml"

with library.open() as lib:
return parse_yaml_library(lib)


result = resolve_components_and_cnx(input_compo)
def test_parsing_components_ok(input_component):
assert len(input_component.components) == 2
assert len(input_component.nodes) == 1
assert len(input_component.connections) == 2

result = resolve_components_and_cnx(input_component)

assert len(result.components) == 3
assert len(result.connections) == 2


def test_consistency_check_ok(input_component, input_library):
result_comp = resolve_components_and_cnx(input_component)
result_lib = resolve_library(input_library)
consistency_check(result_comp.components, result_lib.models)


def test_consistency_check_ko(input_component, input_library):
result_comp = resolve_components_and_cnx(input_component)
result_lib = resolve_library(input_library)
result_lib.models.pop("generator")
with pytest.raises(
ValueError,
match=r"Error: Component G has invalid model ID: generator",
):
consistency_check(result_comp.components, result_lib.models)

0 comments on commit e653f79

Please sign in to comment.