Skip to content

Commit a7528da

Browse files
committed
refactor: merge single speed and variable speed compressor train code
1 parent dc1a8d4 commit a7528da

1 file changed

Lines changed: 27 additions & 59 deletions

File tree

  • src/libecalc/domain/process/compressor/core/train

src/libecalc/domain/process/compressor/core/train/base.py

Lines changed: 27 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from abc import ABC, abstractmethod
1+
from abc import ABC
22
from collections.abc import Callable
33
from functools import partial
44
from typing import Generic, TypeVar, cast
@@ -69,13 +69,6 @@ def _register_pressure_control_strategies(cls):
6969
FixedSpeedPressureControl.COMMON_ASV: cls._evaluate_train_with_common_asv,
7070
}
7171

72-
def _get_inlet_stream(self, pressure_bara: float, temperature_kelvin: float) -> FluidStream:
73-
"""Helper to create a FluidStream for a given pressure and temperature."""
74-
return self.fluid.get_fluid_stream(
75-
pressure_bara=pressure_bara,
76-
temperature_kelvin=temperature_kelvin,
77-
)
78-
7972
def _create_constraints(
8073
self,
8174
suction_pressure: float,
@@ -241,28 +234,6 @@ def evaluate(
241234
],
242235
)
243236

244-
@abstractmethod
245-
def evaluate_given_constraints(
246-
self, constraints: CompressorTrainEvaluationInput
247-
) -> CompressorTrainResultSingleTimeStep:
248-
"""
249-
Evaluate the compressor model based on the set constraints.
250-
251-
The constraints can be:
252-
* Rate (train inlet)
253-
* Additional rates for each stream (if multiple streams)
254-
* Suction pressure (train inlet)
255-
* Discharge pressure (train outlet)
256-
* Intermediate pressure (inter-stage)
257-
* Speed (if variable speed)
258-
259-
The evaluation is done for a single time step.
260-
261-
Return:
262-
CompressorTrainResultSingleTimeStep: The result of the compressor train evaluation.
263-
"""
264-
...
265-
266237
def calculate_pressure_ratios_per_stage(
267238
self,
268239
suction_pressure: NDArray[np.float64] | float,
@@ -983,19 +954,21 @@ def _get_max_std_rate_single_timestep(
983954
Standard volume rate [Sm3/day]
984955
985956
"""
986-
inlet_stream = self._get_inlet_stream(
987-
pressure_bara=constraints.suction_pressure, # type: ignore[arg-type]
957+
assert constraints.suction_pressure is not None
958+
assert constraints.rate is not None
959+
inlet_density = self.fluid_factory.create_stream_from_standard_rate(
960+
pressure_bara=constraints.suction_pressure,
988961
temperature_kelvin=self.stages[0].inlet_temperature_kelvin,
989-
)
990-
inlet_density = inlet_stream.density
962+
standard_rate_m3_per_day=constraints.rate,
963+
).density
991964

992965
def _calculate_train_result(mass_rate: float, speed: float) -> CompressorTrainResultSingleTimeStep:
993966
"""Partial function of self.calculate_compressor_train_given_speed
994967
where we only pass mass_rate.
995968
"""
996969
return self.calculate_compressor_train(
997970
constraints=constraints.create_conditions_with_new_input(
998-
new_rate=self.fluid.mass_rate_to_standard_rate(mass_rate_kg_per_hour=mass_rate), # type: ignore[arg-type]
971+
new_rate=self.fluid_factory.mass_rate_to_standard_rate(mass_rate_kg_per_h=mass_rate), # type: ignore[arg-type]
999972
new_speed=speed,
1000973
)
1001974
)
@@ -1006,7 +979,7 @@ def _calculate_train_result_given_ps_pd(mass_rate: float) -> CompressorTrainResu
1006979
"""
1007980
return self.evaluate_given_constraints(
1008981
constraints=constraints.create_conditions_with_new_input(
1009-
new_rate=self.fluid.mass_rate_to_standard_rate(mass_rate_kg_per_hour=mass_rate), # type: ignore[arg-type]
982+
new_rate=self.fluid_factory.mass_rate_to_standard_rate(mass_rate_kg_per_h=mass_rate), # type: ignore[arg-type]
1010983
)
1011984
)
1012985

@@ -1018,17 +991,17 @@ def _calculate_train_result_given_speed_at_stone_wall(
1018991
"""
1019992
assert not isinstance(self.data_transfer_object, SingleSpeedCompressorTrainDTO)
1020993
_max_valid_mass_rate_at_given_speed = maximize_x_given_boolean_condition_function(
1021-
x_min=self.stages[0].compressor_chart.minimum_rate_as_function_of_speed(speed) * inlet_density, # or 0?
1022-
x_max=self.stages[0].compressor_chart.maximum_rate_as_function_of_speed(speed) * inlet_density,
994+
x_min=self.stages[0].compressor_chart.minimum_rate_as_function_of_speed(speed) * inlet_density, # type: ignore[arg-type]
995+
x_max=self.stages[0].compressor_chart.maximum_rate_as_function_of_speed(speed) * inlet_density, # type: ignore[arg-type]
1023996
bool_func=lambda x: _calculate_train_result(mass_rate=x, speed=speed).within_capacity,
1024997
convergence_tolerance=1e-3,
1025998
maximum_number_of_iterations=20,
1026999
)
10271000

10281001
return self.calculate_compressor_train(
10291002
constraints=constraints.create_conditions_with_new_input(
1030-
new_rate=self.fluid.mass_rate_to_standard_rate(
1031-
mass_rate_kg_per_hour=_max_valid_mass_rate_at_given_speed
1003+
new_rate=self.fluid_factory.mass_rate_to_standard_rate(
1004+
mass_rate_kg_per_h=_max_valid_mass_rate_at_given_speed
10321005
), # type: ignore[arg-type]
10331006
new_speed=speed,
10341007
)
@@ -1068,7 +1041,7 @@ def _calculate_train_result_given_speed_at_stone_wall(
10681041
mass_rate=max_mass_rate_at_max_speed_first_stage
10691042
)
10701043
result_max_mass_rate_at_min_speed_first_stage = _calculate_train_result_at_min_speed_given_mass_rate(
1071-
mass_rate=max_mass_rate_at_min_speed_first_stage
1044+
mass_rate=max_mass_rate_at_min_speed_first_stage # type: ignore[arg-type]
10721045
)
10731046

10741047
# Ensure that the minimum mass rate at max speed is valid for the whole train.
@@ -1171,7 +1144,7 @@ def _calculate_train_result_given_speed_at_stone_wall(
11711144
if not result_max_mass_rate_at_min_speed_first_stage.within_capacity:
11721145
max_mass_rate_at_min_speed = maximize_x_given_boolean_condition_function(
11731146
x_min=EPSILON,
1174-
x_max=max_mass_rate_at_min_speed_first_stage,
1147+
x_max=max_mass_rate_at_min_speed_first_stage, # type: ignore[arg-type]
11751148
bool_func=lambda x: _calculate_train_result_at_min_speed_given_mass_rate(
11761149
mass_rate=x
11771150
).within_capacity,
@@ -1217,11 +1190,11 @@ def _calculate_train_result_given_speed_at_stone_wall(
12171190
# Check that rate_to_return, suction_pressure and discharge_pressure does not require too much power.
12181191
# If so, reduce rate such that power comes below maximum power
12191192
if not self.data_transfer_object.maximum_power:
1220-
return self.fluid.mass_rate_to_standard_rate(mass_rate_kg_per_hour=rate_to_return)
1193+
return self.fluid_factory.mass_rate_to_standard_rate(mass_rate_kg_per_h=rate_to_return)
12211194
elif (
12221195
self.evaluate_given_constraints(
12231196
constraints=constraints.create_conditions_with_new_input(
1224-
new_rate=self.fluid.mass_rate_to_standard_rate(mass_rate_kg_per_hour=rate_to_return), # type: ignore[arg-type]
1197+
new_rate=self.fluid_factory.mass_rate_to_standard_rate(mass_rate_kg_per_h=rate_to_return), # type: ignore[arg-type]
12251198
)
12261199
).power_megawatt
12271200
> self.data_transfer_object.maximum_power
@@ -1238,13 +1211,13 @@ def _calculate_train_result_given_speed_at_stone_wall(
12381211
else:
12391212
# iterate between rate with minimum power, and the previously found rate to return, to find the
12401213
# maximum rate that gives power consumption below maximum power
1241-
return self.fluid.mass_rate_to_standard_rate(
1242-
mass_rate_kg_per_hour=find_root(
1214+
return self.fluid_factory.mass_rate_to_standard_rate(
1215+
mass_rate_kg_per_h=find_root(
12431216
lower_bound=result_with_minimum_rate.stage_results[0].mass_rate_asv_corrected_kg_per_hour,
12441217
upper_bound=rate_to_return,
12451218
func=lambda x: self.evaluate_given_constraints(
12461219
constraints=constraints.create_conditions_with_new_input(
1247-
new_rate=self.fluid.mass_rate_to_standard_rate(mass_rate_kg_per_hour=x), # type: ignore[arg-type]
1220+
new_rate=self.fluid_factory.mass_rate_to_standard_rate(mass_rate_kg_per_h=x), # type: ignore[arg-type]
12481221
)
12491222
).power_megawatt
12501223
- maximum_power * (1 - POWER_CALCULATION_TOLERANCE),
@@ -1254,7 +1227,7 @@ def _calculate_train_result_given_speed_at_stone_wall(
12541227
)
12551228
else:
12561229
# maximum power defined, but found rate is below maximum power
1257-
return self.fluid.mass_rate_to_standard_rate(mass_rate_kg_per_hour=rate_to_return)
1230+
return self.fluid_factory.mass_rate_to_standard_rate(mass_rate_kg_per_h=rate_to_return)
12581231

12591232
def calculate_compressor_train(
12601233
self,
@@ -1279,41 +1252,36 @@ def calculate_compressor_train(
12791252
message="Compressor train calculation requires rate and suction pressure to be set.",
12801253
)
12811254
# Initialize stream at inlet of first compressor stage using fluid properties and inlet conditions
1282-
train_inlet_stream = self._get_inlet_stream(
1255+
train_inlet_stream = self.fluid_factory.create_stream_from_standard_rate(
12831256
pressure_bara=constraints.suction_pressure - self.stages[0].pressure_drop_ahead_of_stage, # type: ignore[operator]
12841257
temperature_kelvin=self.stages[0].inlet_temperature_kelvin,
1258+
standard_rate_m3_per_day=constraints.rate,
12851259
)
1286-
mass_rate_kg_per_hour = self.fluid.standard_rate_to_mass_rate(standard_rates=constraints.rate)
12871260
stage_results: list[CompressorTrainStageResultSingleTimeStep] = []
12881261
outlet_stream = train_inlet_stream
12891262
for stage in self.stages:
12901263
inlet_stream = outlet_stream
12911264
stage_result = stage.evaluate(
12921265
inlet_stream_stage=inlet_stream,
12931266
speed=constraints.speed,
1294-
mass_rate_kg_per_hour=mass_rate_kg_per_hour, # type: ignore[arg-type]
12951267
asv_rate_fraction=asv_rate_fraction,
12961268
asv_additional_mass_rate=asv_additional_mass_rate,
12971269
)
12981270
stage_results.append(stage_result)
12991271

13001272
# We need to recreate the domain object from the result object. This needs cleaning up.
1301-
outlet_stream = inlet_stream.set_new_pressure_and_temperature(
1302-
new_pressure_bara=stage_result.outlet_stream.pressure_bara,
1303-
new_temperature_kelvin=stage_result.outlet_stream.temperature_kelvin,
1304-
)
1305-
1273+
outlet_stream = stage_result.outlet_stream
13061274
# check if target pressures are met
13071275
target_pressure_status = self.check_target_pressures(
13081276
constraints=constraints,
13091277
results=stage_results,
13101278
)
13111279

13121280
return CompressorTrainResultSingleTimeStep(
1313-
inlet_stream=FluidStreamDTO.from_fluid_domain_object(fluid_stream=train_inlet_stream),
1314-
outlet_stream=FluidStreamDTO.from_fluid_domain_object(fluid_stream=outlet_stream),
1281+
inlet_stream=train_inlet_stream,
1282+
outlet_stream=outlet_stream,
13151283
stage_results=stage_results,
1316-
speed=constraints.speed if constraints.speed is not None else float("nan"),
1284+
speed=constraints.speed, # type: ignore[arg-type]
13171285
above_maximum_power=sum([stage_result.power_megawatt for stage_result in stage_results])
13181286
> self.maximum_power
13191287
if self.maximum_power

0 commit comments

Comments
 (0)