Skip to content
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

refactor: move target pressure status from stages to compressor train #589

Merged
merged 1 commit into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 28 additions & 40 deletions src/libecalc/core/models/compressor/results.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
CompressorStageResult,
CompressorStreamCondition,
CompressorTrainCommonShaftFailureStatus,
StageTargetPressureStatus,
TargetPressureStatus,
)
from libecalc.dto.types import ChartAreaFlag

Expand Down Expand Up @@ -51,7 +51,6 @@ class CompressorTrainStageResultSingleTimeStep(BaseModel):
power_megawatt: float

chart_area_flag: ChartAreaFlag
target_pressure_status: StageTargetPressureStatus

rate_has_recirculation: Optional[bool] = None
rate_exceeds_maximum: Optional[bool] = None
Expand Down Expand Up @@ -92,15 +91,11 @@ def create_empty(cls) -> CompressorTrainStageResultSingleTimeStep:
inlet_pressure_before_choking=np.nan,
outlet_pressure_before_choking=np.nan,
point_is_valid=True,
target_pressure_status=StageTargetPressureStatus.NOT_CALCULATED,
)

@property
def is_valid(self) -> bool:
return self.within_capacity and self.target_pressure_status in (
StageTargetPressureStatus.TARGET_PRESSURES_MET,
StageTargetPressureStatus.NOT_CALCULATED,
)
return self.within_capacity

@property
def within_capacity(self) -> bool:
Expand Down Expand Up @@ -141,6 +136,7 @@ class CompressorTrainResultSingleTimeStep(BaseModel):
speed: float
stage_results: List[CompressorTrainStageResultSingleTimeStep]
above_maximum_power: bool = False
target_pressure_status: TargetPressureStatus

@staticmethod
def from_result_list_to_dto(
Expand Down Expand Up @@ -380,39 +376,30 @@ def from_result_list_to_dto(
@property
def failure_status(self):
if not all(r.is_valid for r in self.stage_results):
for i, stage in enumerate(self.stage_results):
if not stage.is_valid:
if not stage.within_capacity:
if stage.chart_area_flag in (
ChartAreaFlag.ABOVE_MAXIMUM_FLOW_RATE,
ChartAreaFlag.BELOW_MINIMUM_SPEED_AND_ABOVE_MAXIMUM_FLOW_RATE,
):
return CompressorTrainCommonShaftFailureStatus.ABOVE_MAXIMUM_FLOW_RATE
elif stage.chart_area_flag in (
ChartAreaFlag.BELOW_MINIMUM_FLOW_RATE,
ChartAreaFlag.BELOW_MINIMUM_SPEED_AND_BELOW_MINIMUM_FLOW_RATE,
):
return CompressorTrainCommonShaftFailureStatus.BELOW_MINIMUM_FLOW_RATE
elif stage.target_pressure_status == StageTargetPressureStatus.ABOVE_TARGET_SUCTION_PRESSURE:
if i == 0: # first stage
return CompressorTrainCommonShaftFailureStatus.TARGET_DISCHARGE_PRESSURE_TOO_HIGH
else:
return CompressorTrainCommonShaftFailureStatus.TARGET_INTERMEDIATE_PRESSURE_TOO_LOW
elif stage.target_pressure_status == StageTargetPressureStatus.BELOW_TARGET_SUCTION_PRESSURE:
if i == 0: # first stage
return CompressorTrainCommonShaftFailureStatus.TARGET_SUCTION_PRESSURE_TOO_HIGH
else:
return CompressorTrainCommonShaftFailureStatus.TARGET_INTERMEDIATE_PRESSURE_TOO_HIGH
elif stage.target_pressure_status == StageTargetPressureStatus.ABOVE_TARGET_DISCHARGE_PRESSURE:
if i == len(self.stage_results) - 1: # last stage
return CompressorTrainCommonShaftFailureStatus.TARGET_DISCHARGE_PRESSURE_TOO_LOW
else:
return CompressorTrainCommonShaftFailureStatus.TARGET_INTERMEDIATE_PRESSURE_TOO_LOW
elif stage.target_pressure_status == StageTargetPressureStatus.BELOW_TARGET_DISCHARGE_PRESSURE:
if i == len(self.stage_results) - 1: # last stage
return CompressorTrainCommonShaftFailureStatus.TARGET_DISCHARGE_PRESSURE_TOO_HIGH
else:
return CompressorTrainCommonShaftFailureStatus.TARGET_INTERMEDIATE_PRESSURE_TOO_HIGH
for stage in self.stage_results:
if not stage.within_capacity:
if stage.chart_area_flag in (
ChartAreaFlag.ABOVE_MAXIMUM_FLOW_RATE,
ChartAreaFlag.BELOW_MINIMUM_SPEED_AND_ABOVE_MAXIMUM_FLOW_RATE,
):
return CompressorTrainCommonShaftFailureStatus.ABOVE_MAXIMUM_FLOW_RATE
elif stage.chart_area_flag in (
ChartAreaFlag.BELOW_MINIMUM_FLOW_RATE,
ChartAreaFlag.BELOW_MINIMUM_SPEED_AND_BELOW_MINIMUM_FLOW_RATE,
):
return CompressorTrainCommonShaftFailureStatus.BELOW_MINIMUM_FLOW_RATE
if self.target_pressure_status == TargetPressureStatus.ABOVE_TARGET_SUCTION_PRESSURE:
return CompressorTrainCommonShaftFailureStatus.TARGET_DISCHARGE_PRESSURE_TOO_HIGH
elif self.target_pressure_status == TargetPressureStatus.BELOW_TARGET_SUCTION_PRESSURE:
return CompressorTrainCommonShaftFailureStatus.TARGET_SUCTION_PRESSURE_TOO_HIGH
elif self.target_pressure_status == TargetPressureStatus.ABOVE_TARGET_DISCHARGE_PRESSURE:
return CompressorTrainCommonShaftFailureStatus.TARGET_DISCHARGE_PRESSURE_TOO_LOW
elif self.target_pressure_status == TargetPressureStatus.BELOW_TARGET_DISCHARGE_PRESSURE:
return CompressorTrainCommonShaftFailureStatus.TARGET_DISCHARGE_PRESSURE_TOO_HIGH
elif self.target_pressure_status == TargetPressureStatus.ABOVE_TARGET_INTERMEDIATE_PRESSURE:
return CompressorTrainCommonShaftFailureStatus.TARGET_INTERMEDIATE_PRESSURE_TOO_LOW
elif self.target_pressure_status == TargetPressureStatus.BELOW_TARGET_INTERMEDIATE_PRESSURE:
return CompressorTrainCommonShaftFailureStatus.TARGET_INTERMEDIATE_PRESSURE_TOO_HIGH
elif self.above_maximum_power:
return CompressorTrainCommonShaftFailureStatus.ABOVE_MAXIMUM_POWER

Expand Down Expand Up @@ -624,4 +611,5 @@ def create_empty(cls, number_of_stages: int) -> CompressorTrainResultSingleTimeS
return cls(
speed=np.nan,
stage_results=[CompressorTrainStageResultSingleTimeStep.create_empty()] * number_of_stages,
target_pressure_status=TargetPressureStatus.NOT_CALCULATED,
)
38 changes: 38 additions & 0 deletions src/libecalc/core/models/compressor/train/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
from libecalc.core.models.compressor.base import CompressorModel
from libecalc.core.models.compressor.results import CompressorTrainResultSingleTimeStep
from libecalc.core.models.compressor.train.fluid import FluidStream
from libecalc.core.models.compressor.train.utils.common import PRESSURE_CALCULATION_TOLERANCE
from libecalc.core.models.compressor.utils import map_compressor_train_stage_to_domain
from libecalc.core.models.results import CompressorTrainResult
from libecalc.core.models.results.compressor import TargetPressureStatus
from libecalc.domain.stream_conditions import StreamConditions
from libecalc.dto.models.compressor.train import CompressorTrain as CompressorTrainDTO
from libecalc.dto.models.compressor.train import (
Expand Down Expand Up @@ -228,3 +230,39 @@ def calculate_pressure_ratios_per_stage(
discharge_pressure, suction_pressure, out=np.ones_like(suction_pressure), where=suction_pressure != 0
)
return pressure_ratios ** (1.0 / len(self.stages))

def check_target_pressures(
self,
calculated_suction_pressure: float,
calculated_discharge_pressure: float,
calculated_intermediate_pressure: Optional[float] = None,
) -> TargetPressureStatus:
"""Check to see how the calculated pressures compare to the required pressures
Args:
calculated_suction_pressure: The calculated suction pressure
calculated_discharge_pressure: The calculated discharge pressure
calculated_intermediate_pressure: The calculated intermediate pressure
Returns:
TargetPressureStatus
"""
if self.target_suction_pressure:
if (calculated_suction_pressure / self.target_suction_pressure) - 1 > PRESSURE_CALCULATION_TOLERANCE:
return TargetPressureStatus.ABOVE_TARGET_SUCTION_PRESSURE
if (self.target_suction_pressure / calculated_suction_pressure) - 1 > PRESSURE_CALCULATION_TOLERANCE:
return TargetPressureStatus.BELOW_TARGET_SUCTION_PRESSURE
if self.target_discharge_pressure:
if (calculated_discharge_pressure / self.target_discharge_pressure) - 1 > PRESSURE_CALCULATION_TOLERANCE:
return TargetPressureStatus.ABOVE_TARGET_DISCHARGE_PRESSURE
if (self.target_discharge_pressure / calculated_discharge_pressure) - 1 > PRESSURE_CALCULATION_TOLERANCE:
return TargetPressureStatus.BELOW_TARGET_DISCHARGE_PRESSURE
if self.target_intermediate_pressure:
if (
calculated_intermediate_pressure / self.target_intermediate_pressure
) - 1 > PRESSURE_CALCULATION_TOLERANCE:
return TargetPressureStatus.ABOVE_TARGET_INTERMEDIATE_PRESSURE
if (
self.target_intermediate_pressure / calculated_intermediate_pressure
) - 1 > PRESSURE_CALCULATION_TOLERANCE:
return TargetPressureStatus.BELOW_TARGET_INTERMEDIATE_PRESSURE

return TargetPressureStatus.TARGET_PRESSURES_MET
31 changes: 23 additions & 8 deletions src/libecalc/core/models/compressor/train/simplified_train.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
)
from libecalc.core.models.compressor.utils import map_compressor_train_stage_to_domain
from libecalc.core.models.results.compressor import (
StageTargetPressureStatus,
TargetPressureStatus,
)
from libecalc.dto.types import ChartAreaFlag

Expand Down Expand Up @@ -127,6 +127,7 @@ def _evaluate_rate_ps_pd(

mass_rate_kg_per_hour = self.fluid.standard_rate_to_mass_rate(standard_rates=rate)
compressor_stages_result_per_time_step = []
compressor_result_per_time_step = []
inlet_pressure = suction_pressure.copy()
for stage in self.stages:
inlet_temperatures_kelvin = np.full_like(rate, fill_value=stage.inlet_temperature_kelvin, dtype=float)
Expand All @@ -142,13 +143,27 @@ def _evaluate_rate_ps_pd(
inlet_pressure = inlet_pressure * pressure_ratios_per_stage

# Converting from individual stage results to a train results and adding max rate per time step.
return [
CompressorTrainResultSingleTimeStep(
speed=np.nan,
stage_results=[result[time_step].stage_results[0] for result in compressor_stages_result_per_time_step],
for time_step in range(len(compressor_stages_result_per_time_step[0])):
self.target_suction_pressure = suction_pressure[time_step]
self.target_discharge_pressure = discharge_pressure[time_step]
compressor_result_per_time_step.append(
CompressorTrainResultSingleTimeStep(
speed=np.nan,
stage_results=[
result[time_step].stage_results[0] for result in compressor_stages_result_per_time_step
],
target_pressure_status=self.check_target_pressures(
calculated_suction_pressure=compressor_stages_result_per_time_step[0][
time_step
].suction_pressure,
calculated_discharge_pressure=compressor_stages_result_per_time_step[-1][
time_step
].discharge_pressure,
),
)
)
for time_step in range(len(compressor_stages_result_per_time_step[0]))
]

return compressor_result_per_time_step

def calculate_compressor_stage_work_given_outlet_pressure(
self,
Expand Down Expand Up @@ -332,9 +347,9 @@ def efficiency_as_function_of_rate_and_head(rates, heads):
outlet_pressure_before_choking=np.nan, # We do not have this value here
# Assuming choking and ASV. Valid points are to the left and below the compressor chart.
point_is_valid=~np.isnan(power_mw[i]), # power_mw is set to np.NaN if invalid step.
target_pressure_status=StageTargetPressureStatus.TARGET_PRESSURES_MET,
)
],
target_pressure_status=TargetPressureStatus.TARGET_PRESSURES_MET,
)
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@
find_root,
maximize_x_given_boolean_condition_function,
)
from libecalc.core.models.results.compressor import (
StageTargetPressureStatus,
)
from libecalc.dto.types import ChartAreaFlag, FixedSpeedPressureControl

EPSILON = 1e-5
Expand Down Expand Up @@ -207,21 +204,23 @@ def _evaluate_train_result_downstream_choking(
choked_stage_results = deepcopy(train_result.stage_results[0])
choked_stage_results.pressure_is_choked = True
choked_stage_results.inlet_pressure_before_choking = suction_pressure
self.target_suction_pressure = train_result.suction_pressure
self.stages[0].target_suction_pressure = train_result.suction_pressure
choked_stage_results.target_pressure_status = self.stages[0].check_target_pressures(
inlet_stream=choked_stage_results.inlet_stream, outlet_stream=choked_stage_results.outlet_stream
)
train_result.stage_results[0] = choked_stage_results
train_result.target_pressure_status = self.check_target_pressures(
calculated_suction_pressure=train_result.suction_pressure_before_choking,
calculated_discharge_pressure=train_result.discharge_pressure,
)

if train_result.discharge_pressure * (1 + PRESSURE_CALCULATION_TOLERANCE) > discharge_pressure:
# Fixme: Set new outlet pressure (or should we really make new stream - tp_flash?)
choked_stage_results = deepcopy(train_result.stage_results[-1])
choked_stage_results.pressure_is_choked = True
choked_stage_results.outlet_pressure_before_choking = float(choked_stage_results.discharge_pressure)
choked_stage_results.outlet_stream.pressure_bara = discharge_pressure
choked_stage_results.target_pressure_status = StageTargetPressureStatus.TARGET_PRESSURES_MET
train_result.stage_results[-1] = choked_stage_results
train_result.target_pressure_status = self.check_target_pressures(
calculated_suction_pressure=train_result.suction_pressure_before_choking, # because of the potential maximum discharge pressure
calculated_discharge_pressure=train_result.discharge_pressure,
)

return train_result

Expand Down Expand Up @@ -250,12 +249,11 @@ def _evaluate_train_results_upstream_choking(
choked_stage_results = deepcopy(train_result.stage_results[0])
choked_stage_results.pressure_is_choked = True
choked_stage_results.inlet_pressure_before_choking = suction_pressure
self.target_suction_pressure = train_result.suction_pressure
self.stages[0].target_suction_pressure = train_result.suction_pressure
choked_stage_results.target_pressure_status = self.stages[0].check_target_pressures(
inlet_stream=choked_stage_results.inlet_stream, outlet_stream=choked_stage_results.outlet_stream
)
train_result.stage_results[0] = choked_stage_results
train_result.target_pressure_status = self.check_target_pressures(
calculated_suction_pressure=train_result.suction_pressure_before_choking,
calculated_discharge_pressure=train_result.discharge_pressure,
)

return train_result

Expand Down Expand Up @@ -308,17 +306,8 @@ def _evaluate_train_result_asv_pressure(
)
inlet_stream_stage = inlet_stream_train
stage_results = []
for i, stage in enumerate(self.stages):
for stage in self.stages:
outlet_pressure_for_stage = inlet_stream_stage.pressure_bara * pressure_ratio_per_stage
# set stage target pressures for first and last stage
if i == 0:
stage.target_suction_pressure = self.target_suction_pressure
else:
stage.target_suction_pressure = None
if i == self.number_of_compressor_stages - 1:
stage.target_discharge_pressure = self.target_discharge_pressure
else:
stage.target_discharge_pressure = None
stage_result = calculate_single_speed_compressor_stage_given_target_discharge_pressure(
outlet_pressure_stage_bara=outlet_pressure_for_stage,
mass_rate_kg_per_hour=mass_rate_kg_per_hour,
Expand All @@ -332,9 +321,15 @@ def _evaluate_train_result_asv_pressure(
inlet_stream_stage = outlet_stream_stage
stage_results.append(stage_result)

# check if target pressures are met
target_pressure_status = self.check_target_pressures(
calculated_suction_pressure=inlet_stream_train.pressure_bara,
calculated_discharge_pressure=stage_results[-1].outlet_stream.pressure_bara,
)
return CompressorTrainResultSingleTimeStep(
speed=np.nan,
stage_results=stage_results,
target_pressure_status=target_pressure_status,
)
else:
return CompressorTrainResultSingleTimeStep.create_empty(number_of_stages=len(self.stages))
Expand Down Expand Up @@ -689,17 +684,8 @@ def calculate_single_speed_train(
stage_results = []
outlet_stream = train_inlet_stream

for i, (stage, mass_rate_kg_per_hour) in enumerate(zip(self.stages, mass_rate_kg_per_hour_per_stage)):
for stage, mass_rate_kg_per_hour in zip(self.stages, mass_rate_kg_per_hour_per_stage):
inlet_stream = outlet_stream
# set stage target pressures for first and last stage
if i == 0:
stage.target_suction_pressure = self.target_suction_pressure
else:
stage.target_suction_pressure = None
if i == self.number_of_compressor_stages - 1:
stage.target_discharge_pressure = self.target_discharge_pressure
else:
stage.target_discharge_pressure = None
stage_result = stage.evaluate(
inlet_stream_stage=inlet_stream,
mass_rate_kg_per_hour=mass_rate_kg_per_hour,
Expand All @@ -714,12 +700,11 @@ def calculate_single_speed_train(
new_temperature_kelvin=stage_result.outlet_stream.temperature_kelvin,
)

if (
target_discharge_pressure
and not np.isclose(stage_results[-1].discharge_pressure, target_discharge_pressure)
and stage_results[-1].discharge_pressure < target_discharge_pressure
):
stage_results[-1].chart_area_flag = ChartAreaFlag.ABOVE_MAXIMUM_HEAD
# check if target pressures are met
target_pressure_status = self.check_target_pressures(
calculated_suction_pressure=train_inlet_stream.pressure_bara,
calculated_discharge_pressure=outlet_stream.pressure_bara,
)

return CompressorTrainResultSingleTimeStep(
speed=np.nan,
Expand All @@ -728,6 +713,7 @@ def calculate_single_speed_train(
> self.maximum_power
if self.maximum_power
else False,
target_pressure_status=target_pressure_status,
)

def get_max_standard_rate(
Expand Down
Loading