Skip to content

Commit d1effef

Browse files
committed
refactor: raise exception when process system is outside capacity
Instead of returning None we should raise exception when a process system or process unit is outside capacity.
1 parent 70fb8db commit d1effef

10 files changed

Lines changed: 56 additions & 35 deletions

File tree

src/libecalc/domain/process/entities/choke.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def __init__(
1414
def set_target_pressure(self, target_pressure: float) -> None:
1515
self._target_pressure = target_pressure
1616

17-
def propagate_stream(self, inlet_stream: FluidStream) -> FluidStream | None:
17+
def propagate_stream(self, inlet_stream: FluidStream) -> FluidStream:
1818
if self._target_pressure is None:
1919
# Delta pressure = 0, i.e. don't do anything
2020
return inlet_stream

src/libecalc/domain/process/process_solver/solvers/downstream_choke_solver.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@ def __init__(self, target_pressure: float):
88
self._target_pressure = target_pressure
99

1010
def solve(self, process_system: ProcessSystem, inlet_stream: FluidStream) -> FluidStream | None:
11-
outlet_stream = process_system.propagate_stream(inlet_stream=inlet_stream)
1211
downstream_choke = process_system.get_downstream_choke()
1312
assert downstream_choke is not None, "DownstreamChokeSolver needs a downstream choke"
1413

15-
if outlet_stream is None or outlet_stream.pressure_bara <= self._target_pressure:
14+
outlet_stream = process_system.propagate_stream(inlet_stream=inlet_stream)
15+
if outlet_stream.pressure_bara <= self._target_pressure:
1616
# Don't use choke if outlet pressure is below target
1717
return outlet_stream
1818

1919
downstream_choke.set_target_pressure(self._target_pressure)
20-
# Adjust pressure
2120
return process_system.propagate_stream(inlet_stream=inlet_stream)

src/libecalc/domain/process/process_solver/solvers/speed_solver.py

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
1+
import logging
2+
13
from libecalc.domain.process.compressor.core.train.utils.numeric_methods import (
24
find_root,
35
maximize_x_given_boolean_condition_function,
46
)
57
from libecalc.domain.process.process_solver.boundary import Boundary
68
from libecalc.domain.process.process_solver.solver import Solver
9+
from libecalc.domain.process.process_system.process_error import ProcessError
710
from libecalc.domain.process.process_system.process_system import ProcessSystem
811
from libecalc.domain.process.value_objects.fluid_stream import FluidStream
912

13+
logger = logging.getLogger(__name__)
14+
1015

1116
class SpeedSolver(Solver):
1217
def __init__(self, boundary: Boundary, target_pressure: float):
@@ -20,24 +25,36 @@ def solve(
2025
) -> FluidStream | None:
2126
shaft = process_system.get_shaft()
2227

23-
def get_outlet_stream(speed: float) -> FluidStream | None:
28+
def get_outlet_stream(speed: float) -> FluidStream:
2429
shaft.set_speed(speed)
2530
return process_system.propagate_stream(inlet_stream)
2631

2732
maximum_speed = self._boundary.max
28-
maximum_speed_outlet_stream = get_outlet_stream(speed=maximum_speed)
29-
if maximum_speed_outlet_stream is None:
30-
# Outside capacity
31-
return maximum_speed_outlet_stream
33+
try:
34+
maximum_speed_outlet_stream = get_outlet_stream(speed=maximum_speed)
35+
except ProcessError as e:
36+
logger.debug(f"No solution found for maximum speed: {maximum_speed}", exc_info=e)
37+
return None
3238

3339
minimum_speed = self._boundary.min
34-
minimum_speed_outlet_stream = get_outlet_stream(speed=minimum_speed)
35-
if minimum_speed_outlet_stream is None:
40+
try:
41+
minimum_speed_outlet_stream = get_outlet_stream(speed=minimum_speed)
42+
except ProcessError as e:
43+
logger.debug(f"No solution found for minimum speed: {minimum_speed}", exc_info=e)
44+
3645
# rate is above maximum rate for minimum speed. Find the lowest minimum speed which gives a valid result
46+
def bool_speed_func(x):
47+
try:
48+
get_outlet_stream(speed=x)
49+
return True
50+
except ProcessError as e:
51+
logger.debug(f"No solution found for speed: {x}", exc_info=e)
52+
return False
53+
3754
minimum_speed = -maximize_x_given_boolean_condition_function(
3855
x_min=-maximum_speed,
3956
x_max=-minimum_speed,
40-
bool_func=lambda x: get_outlet_stream(speed=x) is not None,
57+
bool_func=bool_speed_func,
4158
)
4259
minimum_speed_outlet_stream = get_outlet_stream(speed=minimum_speed)
4360

@@ -47,17 +64,16 @@ def get_outlet_stream(speed: float) -> FluidStream | None:
4764
<= maximum_speed_outlet_stream.pressure_bara
4865
):
4966
# Solution 1, iterate on speed until target discharge pressure is found
50-
def f(speed: float) -> float:
51-
out = get_outlet_stream(speed=speed)
67+
def root_speed_func(x: float) -> float:
5268
# We should be able to produce an outlet stream since we adjust minimum speed above,
5369
# or exit if max speed is not enough
54-
assert out is not None, "Unable to produce an outlet stream"
70+
out = get_outlet_stream(speed=x)
5571
return out.pressure_bara - self._target_pressure
5672

5773
speed = find_root(
5874
lower_bound=minimum_speed,
5975
upper_bound=maximum_speed,
60-
func=f,
76+
func=root_speed_func,
6177
)
6278
return get_outlet_stream(speed=speed)
6379
elif self._target_pressure < minimum_speed_outlet_stream.pressure_bara:
Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,21 @@
11
from libecalc.domain.process.compressor.core.train.utils.numeric_methods import find_root
2-
from libecalc.domain.process.process_solver.boundary import Boundary
32
from libecalc.domain.process.process_solver.solver import Solver
43
from libecalc.domain.process.process_system.process_system import ProcessSystem
54
from libecalc.domain.process.value_objects.fluid_stream import FluidService, FluidStream
65

76

87
class UpstreamChokeSolver(Solver):
9-
def __init__(self, target_pressure: float, fluid_service: FluidService, inlet_pressure_boundary: Boundary):
8+
def __init__(self, target_pressure: float, fluid_service: FluidService, minimum_pressure: float):
109
self._target_pressure = target_pressure
1110
self._fluid_service = fluid_service
12-
self._inlet_pressure_boundary = inlet_pressure_boundary
11+
self._minimum_pressure = minimum_pressure
1312

1413
def solve(self, process_system: ProcessSystem, inlet_stream: FluidStream) -> FluidStream | None:
1514
upstream_choke = process_system.get_upstream_choke()
1615
assert upstream_choke is not None, "UpstreamChokeSolver needs an upstream choke"
1716

1817
outlet_stream = process_system.propagate_stream(inlet_stream)
19-
20-
if outlet_stream is None or outlet_stream.pressure_bara <= self._target_pressure:
18+
if outlet_stream.pressure_bara <= self._target_pressure:
2119
# Don't use choke if outlet pressure is below target
2220
return outlet_stream
2321

@@ -29,15 +27,13 @@ def get_outlet_pressure(inlet_pressure: float) -> float:
2927
standard_rate_m3_per_day=inlet_stream.standard_rate_sm3_per_day,
3028
)
3129
outlet_stream = process_system.propagate_stream(inlet_stream=choked_inlet_stream)
32-
assert outlet_stream is not None, "Unable to produce an outlet stream"
3330
return outlet_stream.pressure_bara
3431

3532
choked_inlet_pressure = find_root(
36-
lower_bound=self._inlet_pressure_boundary.min,
37-
upper_bound=self._inlet_pressure_boundary.max,
33+
lower_bound=self._minimum_pressure,
34+
upper_bound=inlet_stream.pressure_bara,
3835
func=lambda x: get_outlet_pressure(inlet_pressure=x) - self._target_pressure,
3936
)
4037

4138
upstream_choke.set_target_pressure(choked_inlet_pressure)
42-
4339
return process_system.propagate_stream(inlet_stream=inlet_stream)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from libecalc.common.errors.exceptions import EcalcError
2+
3+
4+
class ProcessError(EcalcError):
5+
def __init__(self, message: str = None):
6+
self.message = message
7+
super().__init__(title=None, message=message)
8+
9+
10+
class OutsideCapacityError(ProcessError):
11+
pass

src/libecalc/domain/process/process_system/process_system.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def get_downstream_choke(self) -> Choke | None:
2828
def get_upstream_choke(self) -> Choke | None:
2929
return self._upstream_choke
3030

31-
def propagate_stream(self, inlet_stream: FluidStream) -> FluidStream | None:
31+
def propagate_stream(self, inlet_stream: FluidStream) -> FluidStream:
3232
process_units: list[ProcessUnit] = []
3333
if self._upstream_choke is not None:
3434
process_units.append(self._upstream_choke)

src/libecalc/domain/process/process_system/process_unit.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55

66
class ProcessUnit(abc.ABC):
77
@abc.abstractmethod
8-
def propagate_stream(self, inlet_stream: FluidStream) -> FluidStream | None: ...
8+
def propagate_stream(self, inlet_stream: FluidStream) -> FluidStream: ...

tests/libecalc/domain/process/conftest.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from libecalc.domain.process.entities.choke import Choke
55
from libecalc.domain.process.entities.shaft import Shaft, VariableSpeedShaft
66
from libecalc.domain.process.process_solver.stream_constraint import PressureStreamConstraint
7+
from libecalc.domain.process.process_system.process_error import OutsideCapacityError
78
from libecalc.domain.process.process_system.process_system import ProcessSystem
89
from libecalc.domain.process.process_system.process_unit import ProcessUnit
910
from libecalc.domain.process.value_objects.chart.chart import ChartData
@@ -137,7 +138,7 @@ def __init__(self, pressure_multiplier: float, fluid_service: FluidService):
137138
self._pressure_multiplier = pressure_multiplier
138139
self._fluid_service = fluid_service
139140

140-
def propagate_stream(self, inlet_stream: FluidStream) -> FluidStream | None:
141+
def propagate_stream(self, inlet_stream: FluidStream) -> FluidStream:
141142
return self._fluid_service.create_stream_from_standard_rate(
142143
fluid_model=inlet_stream.fluid_model,
143144
pressure_bara=inlet_stream.pressure_bara * self._pressure_multiplier,
@@ -177,8 +178,10 @@ def __init__(self, compressor_stage: CompressorTrainStage):
177178
def get_shaft(self) -> Shaft:
178179
return self._compressor_stage.compressor.shaft
179180

180-
def propagate_stream(self, inlet_stream: FluidStream) -> FluidStream | None:
181+
def propagate_stream(self, inlet_stream: FluidStream) -> FluidStream:
181182
result = self._compressor_stage.evaluate(inlet_stream_stage=inlet_stream)
183+
if not result.within_capacity:
184+
raise OutsideCapacityError("Unable to produce an outlet stream, operational point is outside capacity.")
182185
return result.outlet_stream
183186

184187

tests/libecalc/domain/process/solvers/test_speed_solver.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def __init__(self, shaft: Shaft, fluid_service: FluidService):
1212
self._shaft = shaft
1313
self._fluid_service = fluid_service
1414

15-
def propagate_stream(self, inlet_stream: FluidStream) -> FluidStream | None:
15+
def propagate_stream(self, inlet_stream: FluidStream) -> FluidStream:
1616
speed = self._shaft.get_speed()
1717
return self._fluid_service.create_stream_from_standard_rate(
1818
fluid_model=inlet_stream.fluid_model,

tests/libecalc/domain/process/solvers/test_upstream_choke_solver.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
from libecalc.domain.process.compressor.core.train.utils.common import EPSILON
44
from libecalc.domain.process.entities.choke import Choke
5-
from libecalc.domain.process.process_solver.boundary import Boundary
65
from libecalc.domain.process.process_solver.solvers.upstream_choke_solver import UpstreamChokeSolver
76

87

@@ -33,10 +32,7 @@ def test_upstream_choke_solver(
3332
upstream_choke_solver = UpstreamChokeSolver(
3433
fluid_service=fluid_service,
3534
target_pressure=target_pressure,
36-
inlet_pressure_boundary=Boundary(
37-
min=EPSILON, # Should be higher than pressure drop ahead of first stage
38-
max=target_pressure,
39-
),
35+
minimum_pressure=EPSILON,
4036
)
4137
outlet_stream = upstream_choke_solver.solve(process_system, inlet_stream)
4238

0 commit comments

Comments
 (0)