1616)
1717from libecalc .domain .process .compressor .core .train .stage import CompressorTrainStage
1818from libecalc .domain .process .compressor .core .train .train_evaluation_input import CompressorTrainEvaluationInput
19+ from libecalc .domain .process .compressor .core .train .types import StreamPort
1920from libecalc .domain .process .compressor .core .train .utils .common import EPSILON , PRESSURE_CALCULATION_TOLERANCE
2021from libecalc .domain .process .core .results import CompressorTrainResult
2122from libecalc .domain .process .core .results .compressor import TargetPressureStatus
@@ -57,6 +58,14 @@ def __init__(
5758 self .calculate_max_rate = calculate_max_rate
5859 self .stage_number_interstage_pressure = stage_number_interstage_pressure
5960
61+ self .ports : list [StreamPort ] = [
62+ StreamPort (is_inlet_port = True , connected_to_stage_no = 0 )
63+ ] # inlet port for first stage
64+ self .inlet_port_connected_to_stage : dict [int , list [int ]] = {key : [] for key in range (len (self .stages ))}
65+ self .outlet_port_connected_to_stage : dict [int , list [int ]] = {key : [] for key in range (len (self .stages ))}
66+
67+ self ._make_ports_from_splitters_and_mixers ()
68+
6069 @property
6170 def number_of_compressor_stages (self ) -> int :
6271 return len (self .stages )
@@ -101,6 +110,24 @@ def get_consumption_type(self) -> ConsumptionType:
101110 # that consumes FUEL, the turbine is modeled separately.
102111 return ConsumptionType .ELECTRICITY
103112
113+ def _make_ports_from_splitters_and_mixers (self ):
114+ """Create stream ports based on the splitters and mixers defined in each stage."""
115+ for i , stage in enumerate (self .stages ):
116+ # Outlet ports from splitters
117+ if stage .splitter :
118+ for _ in range (stage .splitter .number_of_outputs - 1 ):
119+ self .ports .append (StreamPort (is_inlet_port = False , connected_to_stage_no = i ))
120+ # Inlet ports from mixers
121+ if stage .mixer :
122+ for _ in range (stage .mixer .number_of_inputs - 1 ):
123+ self .ports .append (StreamPort (is_inlet_port = True , connected_to_stage_no = i ))
124+
125+ for i , port in enumerate (self .ports ):
126+ if port .is_inlet_port :
127+ self .inlet_port_connected_to_stage [port .connected_to_stage_no ].append (i )
128+ else :
129+ self .outlet_port_connected_to_stage [port .connected_to_stage_no ].append (i )
130+
104131 def set_evaluation_input (
105132 self ,
106133 rate : NDArray [np .float64 ],
@@ -113,12 +140,16 @@ def set_evaluation_input(
113140 raise DomainValidationException ("Suction pressure is required for model" )
114141 if discharge_pressure is None :
115142 raise DomainValidationException ("Discharge pressure is required for model" )
116-
143+ has_interstage_pressure = any (stage .interstage_pressure_control is not None for stage in self .stages )
144+ if has_interstage_pressure and intermediate_pressure is None :
145+ raise DomainValidationException ("Interstage control pressure is required for model" )
146+ if not has_interstage_pressure and intermediate_pressure is not None :
147+ raise DomainValidationException ("Model is not set up to receive interstage pressure" )
117148 self ._rate = rate
118149 self ._suction_pressure = suction_pressure
119150 self ._discharge_pressure = discharge_pressure
120151 self ._intermediate_pressure = intermediate_pressure
121- self ._fluid_model = fluid_model
152+ self ._fluid_model = fluid_model if isinstance ( fluid_model , list ) else [ fluid_model ]
122153
123154 def reset_rate_modifiers (self ):
124155 for stage in self .stages :
@@ -168,17 +199,14 @@ def evaluate(
168199 self .reset_rate_modifiers ()
169200 if isinstance (rate_value , np .ndarray ):
170201 rate_value = list (rate_value )
171- constraints_rate = rate_value [0 ]
172- constraints_stream_rates = rate_value
202+ constraints_rates = rate_value
173203 else :
174- constraints_rate = rate_value
175- constraints_stream_rates = None
204+ constraints_rates = [rate_value ]
176205 evaluation_constraints = CompressorTrainEvaluationInput (
177- rate = constraints_rate ,
178206 suction_pressure = suction_pressure_value ,
179207 discharge_pressure = discharge_pressure_value ,
180208 interstage_pressure = intermediate_pressure_value ,
181- stream_rates = constraints_stream_rates ,
209+ rates = constraints_rates ,
182210 )
183211 train_results .append (self .evaluate_given_constraints (constraints = evaluation_constraints ))
184212
@@ -250,8 +278,9 @@ def train_inlet_stream(
250278 """Find inlet stream given constraints.
251279
252280 Args:
253- constraints (CompressorTrainEvaluationInput): The constraints for the evaluation.
254-
281+ pressure: Inlet pressure [bara].
282+ temperature: Inlet temperature [K].
283+ rate: Standard volume rate [Sm3/day].
255284 Returns:
256285 FluidStream: Inlet fluid stream at the compressor train inlet.
257286 """
@@ -296,7 +325,7 @@ def check_target_pressures(
296325 train_suction_pressure = results .suction_pressure
297326 calculated_discharge_pressure = results .discharge_pressure
298327 stage_suction_pressure = results .stage_results [0 ].inlet_stream .pressure_bara
299- if constraints .stream_rates is not None :
328+ if constraints .rates is not None :
300329 calculated_intermediate_pressure = (
301330 results .stage_results [self .stage_number_interstage_pressure - 1 ].discharge_pressure
302331 if self .stage_number_interstage_pressure is not None
@@ -347,7 +376,13 @@ def get_max_standard_rate(
347376 If the maximum rate cannot be determined, it returns INVALID_MAX_RATE for that time step.
348377 """
349378 if fluid_model is not None :
350- self ._fluid_model = fluid_model
379+ self ._fluid_model = [fluid_model ]
380+
381+ # Check for multiple ports
382+ if len (self .ports ) > 1 :
383+ raise DomainValidationException (
384+ "Calculation of max standard rate is not well defined for compressor trains with more than one port."
385+ )
351386
352387 max_standard_rate = np .full_like (suction_pressures , fill_value = INVALID_MAX_RATE , dtype = float )
353388 for i , (suction_pressure_value , discharge_pressure_value ) in enumerate (
@@ -359,7 +394,7 @@ def get_max_standard_rate(
359394 constraints = CompressorTrainEvaluationInput (
360395 suction_pressure = suction_pressure_value ,
361396 discharge_pressure = discharge_pressure_value ,
362- rate = EPSILON ,
397+ rates = [ EPSILON ] ,
363398 )
364399 try :
365400 max_standard_rate [i ] = self ._get_max_std_rate_single_timestep (constraints = constraints )
0 commit comments