Skip to content

Commit

Permalink
feat: train v2 yaml and dto (#272)
Browse files Browse the repository at this point in the history
  • Loading branch information
jsolaas authored Nov 10, 2023
1 parent 6f63e40 commit b0e3466
Show file tree
Hide file tree
Showing 13 changed files with 364 additions and 165 deletions.
1 change: 1 addition & 0 deletions src/libecalc/dto/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class ComponentType(str, Enum):
GENERIC = "GENERIC"
# TURBINE = "TURBINE"
DIRECT_EMITTER = "DIRECT_EMITTER"
TRAIN_V2 = "TRAIN@V2"

def __lt__(self, other: "ComponentType"): # type: ignore[override]
if self == other:
Expand Down
20 changes: 20 additions & 0 deletions src/libecalc/dto/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,9 +176,29 @@ class PumpComponent(BaseConsumer):
energy_usage_model: Dict[datetime, PumpModel]


class Stream(EcalcBaseModel):
class Config:
allow_population_by_field_name = True

stream_name: Optional[str] = Field(None)
from_component_id: str
to_component_id: str


ConsumerComponent = TypeVar("ConsumerComponent", bound=Union[CompressorComponent, PumpComponent])


class TrainComponent(BaseConsumer):
component_type: Literal[ComponentType.TRAIN_V2] = Field(
ComponentType.TRAIN_V2,
title="TYPE",
description="The type of the component",
alias="TYPE",
)
stages: List[ConsumerComponent]
streams: List[Stream]


class ExpressionTimeSeries(EcalcBaseModel):
value: ExpressionType
unit: Unit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
from libecalc.dto.types import ConsumptionType
from libecalc.expression import Expression
from libecalc.expression.expression import ExpressionType
from libecalc.presentation.yaml.mappers.utils import resolve_and_validate_reference
from libecalc.presentation.yaml.yaml_entities import References
from libecalc.presentation.yaml.yaml_types.components.system.yaml_system_component_conditions import (
YamlSystemComponentConditions,
)
from libecalc.presentation.yaml.yaml_types.components.train.yaml_train import YamlTrain
from libecalc.presentation.yaml.yaml_types.components.yaml_base import (
YamlConsumerBase,
)
Expand All @@ -37,63 +37,7 @@
YamlConsumerStreamConditionsMap = Dict[ConsumerID, YamlConsumerStreamConditions]
YamlPriorities = Dict[PriorityID, YamlConsumerStreamConditionsMap]


def map_consumer(
consumer: Union[YamlPump, YamlCompressor],
consumes: ConsumptionType,
regularity: Dict[datetime, Expression],
category: str,
target_period: Period,
references: References,
fuel: Optional[Dict[datetime, dto.types.FuelType]],
):
"""
Consumer mapper, should probably call ConsumerMapper, but need to figure out differences between consumer in system
and not in system. i.e. with or without stream conditions.
"""
if consumer.component_type == ComponentType.COMPRESSOR_V2:
return dto.components.CompressorComponent(
consumes=consumes,
regularity=regularity,
name=consumer.name,
user_defined_category=define_time_model_for_period(
consumer.category or category, target_period=target_period
),
fuel=fuel,
energy_usage_model={
timestep: resolve_and_validate_reference(
value=reference,
references=references.models,
)
for timestep, reference in define_time_model_for_period(
consumer.energy_usage_model, target_period=target_period
).items()
},
)
elif consumer.component_type == ComponentType.PUMP_V2:
return dto.components.PumpComponent(
consumes=consumes,
regularity=regularity,
name=consumer.name,
user_defined_category=define_time_model_for_period(
consumer.category or category, target_period=target_period
),
fuel=fuel,
energy_usage_model={
timestep: resolve_and_validate_reference(
value=reference,
references=references.models,
)
for timestep, reference in define_time_model_for_period(
consumer.energy_usage_model, target_period=target_period
).items()
},
)
else:
raise ValueError("Unknown consumer type")


TYamlConsumer = TypeVar("TYamlConsumer", bound=Union[YamlCompressor, YamlPump])
TYamlConsumer = TypeVar("TYamlConsumer", bound=Union[YamlCompressor, YamlPump, YamlTrain[YamlCompressor]])


class YamlConsumerSystem(YamlConsumerBase, GenericModel, Generic[TYamlConsumer]):
Expand Down Expand Up @@ -130,8 +74,7 @@ def to_dto(
fuel: Optional[Dict[datetime, dto.types.FuelType]] = None,
) -> dto.components.ConsumerSystem:
consumers = [
map_consumer(
consumer,
consumer.to_dto(
references=references,
consumes=consumes,
regularity=regularity,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,7 @@

from libecalc.common.string.string_utils import get_duplicates
from libecalc.presentation.yaml.yaml_types import YamlBase


class YamlCrossover(YamlBase):
class Config:
allow_population_by_field_name = True

name: str = Field(
None,
title="NAME",
description="The name of the stream. "
"Can be used to identify the crossover stream in multiple streams compressor train",
)
from_: str = Field(
...,
title="FROM",
description="Target component for crossover",
alias="FROM",
)
to: str = Field(
...,
title="TO",
description="Target component for crossover",
)
from libecalc.presentation.yaml.yaml_types.yaml_stream import YamlCrossover


class YamlSystemComponentConditions(YamlBase):
Expand Down Expand Up @@ -69,8 +47,8 @@ def ensure_one_crossover_out(cls, crossover: Optional[List[YamlCrossover]]):
unique_crossover_out = set(crossover_out)
if len(unique_crossover_out) != len(crossover_out):
raise ValueError(
f"Only one crossover per consumer is currently supported. Component(s) with several crossover streams "
f"are {', '.join(sorted(get_duplicates(crossover_out)))}"
f"Only one crossover out per consumer is currently supported. Component(s) with several crossover "
f"streams are {', '.join(sorted(get_duplicates(crossover_out)))}"
)

return crossover
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from datetime import datetime
from typing import Dict, Generic, List, Literal, Optional, TypeVar

from libecalc import dto
from libecalc.common.time_utils import Period
from libecalc.dto.base import ComponentType
from libecalc.dto.components import Stream, TrainComponent
from libecalc.dto.types import ConsumptionType
from libecalc.expression import Expression
from libecalc.presentation.yaml.yaml_entities import References
from libecalc.presentation.yaml.yaml_types.components.yaml_base import YamlConsumerBase
from libecalc.presentation.yaml.yaml_types.yaml_stream import YamlStream
from pydantic import Field
from pydantic.generics import GenericModel

TYamlConsumer = TypeVar("TYamlConsumer")


class YamlTrain(YamlConsumerBase, GenericModel, Generic[TYamlConsumer]):
component_type: Literal[ComponentType.TRAIN_V2] = Field(
ComponentType.TRAIN_V2,
title="Type",
description="The type of the component",
alias="TYPE",
)
stages: List[TYamlConsumer]
streams: List[YamlStream] = Field(default_factory=list, title="Streams", description="List of streams")

def to_dto(
self,
consumes: ConsumptionType,
regularity: Dict[datetime, Expression],
target_period: Period,
references: References,
category: str,
fuel: Optional[Dict[datetime, dto.types.FuelType]],
):
stages = [
consumer.to_dto(
references=references,
consumes=consumes,
regularity=regularity,
target_period=target_period,
fuel=fuel,
category=self.category or category,
)
for consumer in self.stages
]

stage_name_to_id_map = {stage.name: stage.id for stage in stages}

return TrainComponent(
component_type=self.component_type,
consumes=consumes,
fuel=fuel,
category=self.category or category,
name=self.name,
stages=stages,
streams=[
Stream(
stream_name=stream.name,
from_component_id=stage_name_to_id_map[stream.from_],
to_component_id=stage_name_to_id_map[stream.to],
)
for stream in self.streams
],
)
Original file line number Diff line number Diff line change
Expand Up @@ -13,35 +13,10 @@ class YamlConsumerBase(YamlBase):
description="Consumer name",
)
category: Optional[str] = Field(
...,
None,
title="CATEGORY",
description="User defined category",
)


class YamlOperationalConditionBase(YamlBase):
condition: Optional[ExpressionType] = Field(
None,
title="Condition",
description="""
All consumers may have a keyword CONDITION which specifies conditions for the consumer to be used. \n
At points in the time series where the condition evaluates to 0 (or False), the energy consumption will be 0. \n
This is practical for some otherwise constant consumers, for example, fixed production loads, which have a constant \n
load whenever there is production. CONDITION supports the functionality described in Expressions, \n
but is required to evaluate to True/False or 1/0.\n
""",
)
power_loss_factor: Optional[ExpressionType] = Field(
None,
title="Power loss factor",
alias="POWERLOSSFACTOR", # Legacy support
description="""
A factor that may be added to account for power transmission losses. E.g. if you have a subsea installation with a \n
power line to another installation, there may be line losses. For a power line loss of 5%, POWER_LOSS_FACTOR is set to \n
0.05 and the power required from the power source (generator set) will be:\n\n
power_requirement = power_before_loss / (1 - power_loss_factor)
""",
)


opt_expr_list = Optional[List[ExpressionType]]
Original file line number Diff line number Diff line change
@@ -1,28 +1,25 @@
from typing import Literal, Optional, Union
from datetime import datetime
from typing import Dict, Literal, Optional, Union

from pydantic import Field

from libecalc import dto
from libecalc.common.time_utils import Period, define_time_model_for_period
from libecalc.dto.base import ComponentType
from libecalc.dto.components import CompressorComponent
from libecalc.dto.types import ConsumptionType
from libecalc.expression import Expression
from libecalc.presentation.yaml.mappers.utils import resolve_and_validate_reference
from libecalc.presentation.yaml.yaml_entities import References
from libecalc.presentation.yaml.yaml_types.components.yaml_base import (
YamlConsumerBase,
YamlOperationalConditionBase,
)
from libecalc.presentation.yaml.yaml_types.models import YamlCompressorWithTurbine
from libecalc.presentation.yaml.yaml_types.yaml_temporal_model import YamlTemporalModel

CompressorModel = Union[YamlCompressorWithTurbine]


class YamlCompressorOperationalSettings(YamlOperationalConditionBase):
class Config:
title = "CompressorOperationalSettings"

rate: Optional[Expression]
inlet_pressure: Optional[Expression]
outlet_pressure: Optional[Expression]


class YamlCompressor(YamlConsumerBase):
class Config:
title = "Compressor"
Expand All @@ -34,17 +31,30 @@ class Config:
alias="TYPE",
)

category: Optional[str] = Field(
None,
title="CATEGORY",
description="User defined category",
)
energy_usage_model: YamlTemporalModel[str]


class YamlCompressorStage(YamlCompressor):
class Config:
title = "CompressorStage"

user_defined_category: str
operational_settings: YamlCompressorOperationalSettings
def to_dto(
self,
consumes: ConsumptionType,
regularity: Dict[datetime, Expression],
target_period: Period,
references: References,
category: str,
fuel: Optional[Dict[datetime, dto.types.FuelType]],
):
return CompressorComponent(
consumes=consumes,
regularity=regularity,
name=self.name,
user_defined_category=define_time_model_for_period(self.category or category, target_period=target_period),
fuel=fuel,
energy_usage_model={
timestep: resolve_and_validate_reference(
value=reference,
references=references.models,
)
for timestep, reference in define_time_model_for_period(
self.energy_usage_model, target_period=target_period
).items()
},
)
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from libecalc.presentation.yaml.yaml_types.components.system.yaml_consumer_system import (
YamlConsumerSystem,
)
from libecalc.presentation.yaml.yaml_types.components.train.yaml_train import YamlTrain
from libecalc.presentation.yaml.yaml_types.components.yaml_category_field import (
CategoryField,
)
Expand Down Expand Up @@ -56,7 +57,12 @@ def schema_extra(schema: Dict[str, Any], model: Type["YamlGeneratorSet"]) -> Non
"generator set.\n\n$ECALC_DOCS_KEYWORDS_URL/ELECTRICITY2FUEL",
)
consumers: List[
Union[YamlElectricityConsumer, YamlConsumerSystem[YamlCompressor], YamlConsumerSystem[YamlPump]]
Union[
YamlElectricityConsumer,
YamlConsumerSystem[YamlCompressor],
YamlConsumerSystem[YamlPump],
YamlConsumerSystem[YamlTrain[YamlCompressor]],
]
] = Field(
...,
title="CONSUMERS",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from libecalc.presentation.yaml.yaml_types.components.system.yaml_consumer_system import (
YamlConsumerSystem,
)
from libecalc.presentation.yaml.yaml_types.components.train.yaml_train import YamlTrain
from libecalc.presentation.yaml.yaml_types.components.yaml_category_field import (
CategoryField,
)
Expand Down Expand Up @@ -58,7 +59,12 @@ class Config:
description="Defines one or more generator sets.\n\n$ECALC_DOCS_KEYWORDS_URL/GENERATORSETS",
)
fuelconsumers: List[
Union[YamlFuelConsumer, YamlConsumerSystem[YamlCompressor], YamlConsumerSystem[YamlPump]]
Union[
YamlFuelConsumer,
YamlConsumerSystem[YamlCompressor],
YamlConsumerSystem[YamlPump],
YamlConsumerSystem[YamlTrain[YamlCompressor]],
]
] = Field(
None,
title="FUELCONSUMERS",
Expand Down
Loading

0 comments on commit b0e3466

Please sign in to comment.