diff --git a/src/libecalc/common/stream.py b/src/libecalc/common/stream.py index f44ebce043..bfa2612297 100644 --- a/src/libecalc/common/stream.py +++ b/src/libecalc/common/stream.py @@ -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): diff --git a/src/libecalc/core/consumers/compressor/component.py b/src/libecalc/core/consumers/compressor/component.py index 8b71ac3b5e..314270455a 100644 --- a/src/libecalc/core/consumers/compressor/component.py +++ b/src/libecalc/core/consumers/compressor/component.py @@ -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 @@ -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: @@ -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, diff --git a/src/libecalc/core/consumers/pump/component.py b/src/libecalc/core/consumers/pump/component.py index 5bc9df666a..aa429b155c 100644 --- a/src/libecalc/core/consumers/pump/component.py +++ b/src/libecalc/core/consumers/pump/component.py @@ -66,9 +66,6 @@ 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 = [] @@ -76,11 +73,9 @@ def evaluate( 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) @@ -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( diff --git a/src/libecalc/core/models/compressor/base.py b/src/libecalc/core/models/compressor/base.py index 3dfceffb49..98ef17d163 100644 --- a/src/libecalc/core/models/compressor/base.py +++ b/src/libecalc/core/models/compressor/base.py @@ -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 ( @@ -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, @@ -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], @@ -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], diff --git a/src/libecalc/core/models/compressor/sampled/compressor_model_sampled.py b/src/libecalc/core/models/compressor/sampled/compressor_model_sampled.py index f9feffd841..59120d684f 100644 --- a/src/libecalc/core/models/compressor/sampled/compressor_model_sampled.py +++ b/src/libecalc/core/models/compressor/sampled/compressor_model_sampled.py @@ -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 @@ -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.""" diff --git a/src/libecalc/core/models/compressor/train/base.py b/src/libecalc/core/models/compressor/train/base.py index acd6660ac1..2d625c17d1 100644 --- a/src/libecalc/core/models/compressor/train/base.py +++ b/src/libecalc/core/models/compressor/train/base.py @@ -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 @@ -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." ) diff --git a/src/libecalc/core/models/pump/pump.py b/src/libecalc/core/models/pump/pump.py index 5ba9a52e57..b88f0f9f05 100644 --- a/src/libecalc/core/models/pump/pump.py +++ b/src/libecalc/core/models/pump/pump.py @@ -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 @@ -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] @@ -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. @@ -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), + )