-
Notifications
You must be signed in to change notification settings - Fork 5
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: add stream conditions to compressor v2 #194
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
from typing import Literal | ||
|
||
from libecalc.common.string_utils import to_camel_case | ||
from libecalc.common.utils.rates import TimeSeriesFloat, TimeSeriesRate | ||
from pydantic import BaseModel, Extra | ||
|
||
|
||
class StreamCondition(BaseModel): | ||
class Config: | ||
extra = Extra.forbid | ||
alias_generator = to_camel_case | ||
allow_population_by_field_name = True | ||
|
||
rate: TimeSeriesRate | ||
pressure: TimeSeriesFloat | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. liker denne, tenkte at her må vi spesifisere input og output stream. mye likt der, men trykke har jo naturlig nok forandra seg...og det kan andre ting også gjøre :) blir bra dette...og godt utgangspunkt for diskusjon :) |
||
fluid_density: TimeSeriesFloat = None | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this for pump only? Or both compressor and pump? May easily lead to confusion if there is a difference. Not sure if it makes sense with a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess we could have different types of streams, where pump expects a certain type, and compressor another. But I'm hoping we can find a common interface, where the stream itself can handle density etc. That means using streams as input though, so not yet. But I agree, to be discussed. |
||
|
||
|
||
class Stage(BaseModel): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Name easily confused with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CompressorStage, ASVStage, ChokeStage. I was thinking the common name for all of these were stage, and that is what this represents, so stream is only one of the properties on a stage, might be the only one.. we'll see |
||
class Config: | ||
extra = Extra.forbid | ||
alias_generator = to_camel_case | ||
allow_population_by_field_name = True | ||
|
||
name: Literal["inlet", "before_choke", "outlet"] | ||
stream_condition: StreamCondition | ||
Comment on lines
+8
to
+26
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let me know if we have something similar already in models |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ | |
import numpy as np | ||
from libecalc import dto | ||
from libecalc.common.exceptions import ProgrammingError | ||
from libecalc.common.stream import Stage, StreamCondition | ||
from libecalc.common.temporal_model import TemporalModel | ||
from libecalc.common.units import Unit | ||
from libecalc.common.utils.rates import ( | ||
|
@@ -75,7 +76,7 @@ def evaluate( | |
evaluated_timesteps = [] | ||
|
||
# TODO: This is a false assumption and will be dealt with shortly (that the regularity is the same | ||
# for all timesteps, and only taken for the first timestep) | ||
# for all timesteps, and only taken for the first timestep). Not the first timestep, the first rate | ||
evaluated_regularity = operational_settings.stream_day_rates[0].regularity | ||
for timestep in operational_settings.timesteps: | ||
compressor = self._temporal_model.get_model(timestep) | ||
|
@@ -108,6 +109,24 @@ def evaluate( | |
if energy_usage.unit == Unit.STANDARD_CUBIC_METER_PER_DAY: | ||
energy_usage = energy_usage.to_calendar_day() # provide fuel usage in calendar day, same as legacy consumer | ||
|
||
# Creating a single input rate until we decide how to deal with multiple rates, multiple rates added because of | ||
# multiple streams and pressures model, but we need to look at how streams are defined there. | ||
total_requested_rate = TimeSeriesRate( | ||
timesteps=operational_settings.timesteps, | ||
values=list(np.sum([rate.values for rate in operational_settings.stream_day_rates], axis=0)), | ||
unit=operational_settings.stream_day_rates[0].unit, | ||
regularity=operational_settings.stream_day_rates[0].regularity, | ||
rate_type=operational_settings.stream_day_rates[0].rate_type, | ||
) | ||
|
||
outlet_pressure_before_choke = TimeSeriesFloat( | ||
values=aggregated_result.outlet_pressure_before_choking | ||
if aggregated_result.outlet_pressure_before_choking | ||
else [np.nan for _ in evaluated_timesteps], | ||
timesteps=evaluated_timesteps, | ||
unit=Unit.BARA, | ||
) | ||
|
||
component_result = core_results.CompressorResult( | ||
timesteps=evaluated_timesteps, | ||
power=TimeSeriesRate( | ||
|
@@ -132,13 +151,30 @@ def evaluate( | |
timesteps=evaluated_timesteps, | ||
unit=Unit.NONE, | ||
), | ||
outlet_pressure_before_choking=TimeSeriesFloat( | ||
values=aggregated_result.outlet_pressure_before_choking | ||
if aggregated_result.outlet_pressure_before_choking | ||
else [np.nan for _ in evaluated_timesteps], | ||
timesteps=evaluated_timesteps, | ||
unit=Unit.BARA, | ||
), | ||
outlet_pressure_before_choking=outlet_pressure_before_choke, | ||
stages=[ | ||
Stage( | ||
name="inlet", | ||
stream_condition=StreamCondition( | ||
rate=total_requested_rate, | ||
pressure=operational_settings.inlet_pressure, | ||
), | ||
), | ||
Stage( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be easy to extend this list with more stages from models. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like the start to more structured add the different stage/phases etc of the stream that you are adding though :) |
||
name="before_choke", | ||
stream_condition=StreamCondition( | ||
rate=total_requested_rate, | ||
pressure=outlet_pressure_before_choke, | ||
), | ||
), | ||
Stage( | ||
name="outlet", | ||
stream_condition=StreamCondition( | ||
rate=total_requested_rate, | ||
pressure=operational_settings.outlet_pressure, | ||
), | ||
), | ||
], | ||
) | ||
|
||
return EcalcModelResult( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ | |
from datetime import datetime | ||
from typing import Any, Dict, List, Optional, Union | ||
|
||
from libecalc.common.stream import Stage | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should go to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, core/domain. Hopefully dto will be allowed to use it from core. It isn't all that clear to me anymore why we need a dto layer..We have a yaml layer, and can convert to something else there, why do we need a layer between yaml and core? I'm sure there is a reason, and I'm thinking it has something to do with evaluated vs not evaluated expressions.. It was introduced to allow changes, but in v2 we can make changes in core. I dunno There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's discuss .) |
||
from libecalc.common.tabular_time_series import TabularTimeSeriesUtils | ||
from libecalc.common.utils.rates import ( | ||
TimeSeriesBoolean, | ||
|
@@ -62,6 +63,7 @@ class CompressorResult(GenericComponentResult): | |
recirculation_loss: TimeSeriesRate | ||
rate_exceeds_maximum: TimeSeriesBoolean | ||
outlet_pressure_before_choking: TimeSeriesFloat | ||
stages: List[Stage] = None # Optional because only in v2 | ||
|
||
def get_subset(self, indices: List[int]) -> Self: | ||
return self.__class__( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -108,8 +108,8 @@ def from_yaml_to_dto( | |
|
||
if EcalcYamlKeywords.type in data: | ||
if data[EcalcYamlKeywords.type] == ComponentType.COMPRESSOR_SYSTEM_V2: | ||
compressor_system_yaml = YamlCompressorSystem(**data) | ||
try: | ||
compressor_system_yaml = YamlCompressorSystem(**data) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Improves error message when the yaml is incorrect |
||
return compressor_system_yaml.to_dto( | ||
consumes=consumes, | ||
regularity=regularity, | ||
|
@@ -120,9 +120,8 @@ def from_yaml_to_dto( | |
except ValidationError as e: | ||
raise DtoValidationError(data=data, validation_error=e) from e | ||
if data[EcalcYamlKeywords.type] == ComponentType.PUMP_SYSTEM_V2: | ||
pump_system_yaml = YamlPumpSystem(**data) | ||
|
||
try: | ||
pump_system_yaml = YamlPumpSystem(**data) | ||
return pump_system_yaml.to_dto( | ||
consumes=consumes, | ||
regularity=regularity, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess usage here is in consumer system (only), but the entity should be called
Stream
, and it is theStream
that should be used in consumer system imoThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only consumer system now, but I'm hoping/expecting this to be used for all new components, also in models if we want to introduce TimeSeries there..
It's used in compressor (and when this is approved I will add it to pump) so when we add a pump and compressor v2 (outside system) it will be used there also