Skip to content

Commit

Permalink
refactor: implement evaluate streams in models (#232)
Browse files Browse the repository at this point in the history
This gives models the option to handle streams separately instead of
mixing.
  • Loading branch information
jsolaas authored Oct 11, 2023
1 parent 0c45251 commit df6b6b0
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 30 deletions.
6 changes: 3 additions & 3 deletions src/libecalc/common/stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ def get_subset_for_timestep(self, current_timestep: datetime) -> Self:
)

@classmethod
def mix_all(cls, inlet_streams: List["Stream"]) -> "Stream":
if len(inlet_streams) == 0:
def mix_all(cls, streams: List["Stream"]) -> "Stream":
if len(streams) == 0:
raise ValueError("No streams to mix")
return reduce(Stream.mix, inlet_streams)
return reduce(Stream.mix, streams)


class Stage(BaseModel):
Expand Down
28 changes: 10 additions & 18 deletions src/libecalc/core/consumers/compressor/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,7 @@
TimeSeriesRate,
)
from libecalc.core.consumers.base import BaseConsumerWithoutOperationalSettings
from libecalc.core.models.compressor import CompressorModel, create_compressor_model
from libecalc.core.models.compressor.train.variable_speed_compressor_train_common_shaft_multiple_streams_and_pressures import (
VariableSpeedCompressorTrainCommonShaftMultipleStreamsAndPressures,
)
from libecalc.core.models.compressor import create_compressor_model
from libecalc.core.models.results.compressor import CompressorTrainResult
from libecalc.core.result import EcalcModelResult
from libecalc.core.result import results as core_results
Expand Down Expand Up @@ -72,27 +69,18 @@ def evaluate(
"""
self._operational_settings = operational_settings

# 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_inlet_stream = Stream.mix_all(operational_settings.inlet_streams)

model_results = []
evaluated_timesteps = []

evaluated_regularity = total_requested_inlet_stream.rate.regularity
for timestep in operational_settings.timesteps:
compressor = self._temporal_model.get_model(timestep)
operational_settings_for_timestep = operational_settings.get_subset_for_timestep(timestep)
evaluated_timesteps.extend(operational_settings_for_timestep.timesteps)
if isinstance(compressor, VariableSpeedCompressorTrainCommonShaftMultipleStreamsAndPressures):
raise NotImplementedError("Need to implement this")
elif issubclass(type(compressor), CompressorModel):
model_result = compressor.evaluate_rate_ps_pd(
rate=np.asarray(total_requested_inlet_stream.rate.values),
suction_pressure=np.asarray(total_requested_inlet_stream.pressure.values),
discharge_pressure=np.asarray(operational_settings_for_timestep.outlet_stream.pressure.values),
)
model_results.append(model_result)
model_result = compressor.evaluate_streams(
inlet_streams=operational_settings.inlet_streams,
outlet_stream=operational_settings.outlet_stream,
)
model_results.append(model_result)

aggregated_result: Optional[CompressorTrainResult] = None
for model_result in model_results:
Expand All @@ -101,6 +89,10 @@ def evaluate(
else:
aggregated_result.extend(model_result)

# Mixing all input rates to get total rate passed through compressor. Used when reporting streams.
total_requested_inlet_stream = Stream.mix_all(operational_settings.inlet_streams)
evaluated_regularity = total_requested_inlet_stream.rate.regularity

energy_usage = TimeSeriesRate(
values=aggregated_result.energy_usage,
timesteps=evaluated_timesteps,
Expand Down
15 changes: 7 additions & 8 deletions src/libecalc/core/consumers/pump/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,21 +66,16 @@ def evaluate(
Handle regularity outside
"""
self._operational_settings = operational_settings
total_requested_inlet_stream = Stream.mix_all(operational_settings.inlet_streams)

regularity = total_requested_inlet_stream.rate.regularity

model_results = []
evaluated_timesteps = []
for timestep in operational_settings.timesteps:
pump = self._temporal_model.get_model(timestep)
operational_settings_for_timestep = operational_settings.get_subset_for_timestep(timestep)
evaluated_timesteps.extend(operational_settings_for_timestep.timesteps)
model_result = pump.evaluate_rate_ps_pd_density(
rate=np.asarray(total_requested_inlet_stream.rate.values),
suction_pressures=np.asarray(total_requested_inlet_stream.pressure.values),
discharge_pressures=np.asarray(operational_settings_for_timestep.outlet_stream.pressure.values),
fluid_density=np.asarray(total_requested_inlet_stream.fluid_density.values),
model_result = pump.evaluate_streams(
inlet_streams=operational_settings.inlet_streams,
outlet_stream=operational_settings.outlet_stream,
)
model_results.append(model_result)

Expand All @@ -91,6 +86,10 @@ def evaluate(
else:
aggregated_result.extend(model_result)

# Mixing all input rates to get total rate passed through compressor. Used when reporting streams.
total_requested_inlet_stream = Stream.mix_all(operational_settings.inlet_streams)
regularity = total_requested_inlet_stream.rate.regularity

component_result = core_results.PumpResult(
timesteps=evaluated_timesteps,
power=TimeSeriesRate(
Expand Down
28 changes: 28 additions & 0 deletions src/libecalc/core/models/compressor/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import numpy as np
from libecalc import dto
from libecalc.common.logger import logger
from libecalc.common.stream import Stream
from libecalc.common.units import Unit
from libecalc.core.models.base import BaseModel
from libecalc.core.models.compressor.train.utils.common import (
Expand Down Expand Up @@ -39,6 +40,14 @@ def get_max_standard_rate(
"""
raise NotImplementedError

@abstractmethod
def get_max_standard_rate_from_streams(
self,
inlet_streams: List[Stream],
outlet_stream: Stream,
):
raise NotImplementedError

@abstractmethod
def evaluate_rate_ps_pd(
self,
Expand All @@ -54,6 +63,14 @@ def evaluate_rate_ps_pd(
"""
raise NotImplementedError

@abstractmethod
def evaluate_streams(
self,
inlet_streams: List[Stream],
outlet_stream: Stream,
):
raise NotImplementedError

def validate_operational_conditions(
self,
rate: NDArray[np.float64],
Expand Down Expand Up @@ -275,6 +292,17 @@ def evaluate_rate_ps_pd(
)
)

def evaluate_streams(
self,
inlet_streams: List[Stream],
outlet_stream: Stream,
) -> CompressorTrainResult:
return self.evaluate_turbine_based_on_compressor_model_result(
compressor_energy_function_result=self.compressor_model.evaluate_streams(
inlet_streams=inlet_streams, outlet_stream=outlet_stream
)
)

def evaluate_rate_ps_pint_pd(
self,
rate: NDArray[np.float64],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from libecalc import dto
from libecalc.common.feature_flags import Feature
from libecalc.common.logger import logger
from libecalc.common.stream import Stream
from libecalc.common.units import Unit
from libecalc.common.utils.adjustment import transform_linear
from libecalc.core.models.compressor.base import CompressorModel
Expand Down Expand Up @@ -253,6 +254,18 @@ def evaluate_rate_ps_pd(

return result

def evaluate_streams(
self,
inlet_streams: List[Stream],
outlet_stream: Stream,
) -> CompressorTrainResult:
mixed_input_streams = Stream.mix_all(streams=inlet_streams)
return self.evaluate_rate_ps_pd(
rate=np.asarray(mixed_input_streams.rate.values),
suction_pressure=np.asarray(mixed_input_streams.pressure.values),
discharge_pressure=np.asarray(outlet_stream.pressure.values),
)

@staticmethod
def _get_indices_from_condition(condition: List[bool]) -> List[int]:
"""Return the indices in a list with booleans where the value is True."""
Expand Down
22 changes: 22 additions & 0 deletions src/libecalc/core/models/compressor/train/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from libecalc import dto
from libecalc.common.feature_flags import Feature
from libecalc.common.logger import logger
from libecalc.common.stream import Stream
from libecalc.common.units import Unit
from libecalc.core.models.compressor.base import CompressorModel
from libecalc.core.models.compressor.results import CompressorTrainResultSingleTimeStep
Expand Down Expand Up @@ -138,6 +139,27 @@ def evaluate_rate_ps_pd(
failure_status=[t.failure_status for t in train_results],
)

def evaluate_streams(
self,
inlet_streams: List[Stream],
outlet_stream: Stream,
) -> CompressorTrainResult:
"""
Evaluate model based on inlet streams and the expected outlet stream.
Args:
inlet_streams:
outlet_stream:
Returns:
"""
mixed_inlet_stream = Stream.mix_all(inlet_streams)
return self.evaluate_rate_ps_pd(
rate=np.asarray(mixed_inlet_stream.rate.values),
suction_pressure=np.asarray(mixed_inlet_stream.pressure.values),
discharge_pressure=np.asarray(outlet_stream.pressure.values),
)

@Feature.experimental(
feature_description="Maximum power constraint is an experimental feature where the syntax may change at any time."
)
Expand Down
30 changes: 29 additions & 1 deletion src/libecalc/core/models/pump/pump.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from __future__ import annotations

from abc import abstractmethod
from typing import Union
from typing import List, Union

import numpy as np
from libecalc.common.logger import logger
from libecalc.common.stream import Stream
from libecalc.common.units import Unit, UnitConstants
from libecalc.common.utils.adjustment import transform_linear
from libecalc.core.models.base import BaseModel
Expand Down Expand Up @@ -51,6 +52,14 @@ def evaluate_rate_ps_pd_density(
) -> PumpModelResult:
pass

@abstractmethod
def evaluate_streams(
self,
inlet_streams: List[Stream],
outlet_stream: Stream,
) -> PumpModelResult:
pass

@staticmethod
def _calculate_head(
ps: NDArray[np.float64], pd: NDArray[np.float64], density: Union[NDArray[np.float64], float]
Expand Down Expand Up @@ -212,6 +221,16 @@ def evaluate_rate_ps_pd_density(
return pump_result


def evaluate_streams(self, inlet_streams: List[Stream], outlet_stream: Stream) -> PumpModelResult:
total_requested_stream = Stream.mix_all(inlet_streams)
return self.evaluate_rate_ps_pd_density(
rate=np.asarray(total_requested_stream.rate.values),
suction_pressures=np.asarray(total_requested_stream.pressure.values),
discharge_pressures=np.asarray(outlet_stream.pressure.values),
fluid_density=np.asarray(total_requested_stream.fluid_density.values),
)


def _adjust_for_head_margin(heads: NDArray[np.float64], maximum_heads: NDArray[np.float64], head_margin: float):
"""A method which adjust heads and set head equal to maximum head if head is above maximum
but below maximum + head margin.
Expand Down Expand Up @@ -318,3 +337,12 @@ def evaluate_rate_ps_pd_density(
)

return pump_result

def evaluate_streams(self, inlet_streams: List[Stream], outlet_stream: Stream) -> PumpModelResult:
total_requested_stream = Stream.mix_all(inlet_streams)
return self.evaluate_rate_ps_pd_density(
rate=np.asarray(total_requested_stream.rate.values),
suction_pressures=np.asarray(total_requested_stream.pressure.values),
discharge_pressures=np.asarray(outlet_stream.pressure.values),
fluid_density=np.asarray(total_requested_stream.fluid_density.values),
)

0 comments on commit df6b6b0

Please sign in to comment.