Skip to content

Commit dc68293

Browse files
committed
fix: allow negative rates or split fractions in splitter when within floating point precision
1 parent 0571c97 commit dc68293

3 files changed

Lines changed: 49 additions & 7 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ def split(
281281
]
282282
split_streams = self.splitter.split_stream(
283283
stream=inlet_stream_stage,
284-
split_fractions=all_rates_to_splitter,
284+
rates=all_rates_to_splitter,
285285
)
286286
return split_streams[-1] # The last stream goes to the compressor stage
287287

src/libecalc/domain/process/compressor/core/train/utils/common.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from libecalc.domain.process.compressor.core.train.utils.numeric_methods import DampState, adaptive_pressure_update
55
from libecalc.domain.process.value_objects.fluid_stream import FluidStream
66

7+
FLOATING_POINT_PRECISION = 1e-9
78
EPSILON = 1e-5
89
PRESSURE_CALCULATION_TOLERANCE = 1e-3
910
POWER_CALCULATION_TOLERANCE = 1e-3
Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,74 @@
1+
from libecalc.common.errors.exceptions import IllegalStateException
2+
from libecalc.common.logger import logger
3+
from libecalc.domain.process.compressor.core.train.utils.common import FLOATING_POINT_PRECISION
14
from libecalc.domain.process.value_objects.fluid_stream import FluidStream
25

36

47
class Splitter:
58
def __init__(self, number_of_outputs: int):
69
self.number_of_outputs = number_of_outputs
710

8-
def split_stream(self, stream: FluidStream, split_fractions: list[float]) -> list[FluidStream]:
11+
def split_stream(
12+
self, stream: FluidStream, split_fractions: list[float] | None = None, rates: list[float] | None = None
13+
) -> list[FluidStream]:
914
"""
1015
Splits the fluid stream into streams based on the split fractions.
1116
1217
Args:
1318
stream (FluidStream): The fluid stream to be split.
14-
split_fractions (Sequence[float]): The fractions of the stream to go to the different output streams (0.0 to 1.0).
19+
split_fractions (list[float] | None): The fractions of the stream to go to the different output streams (0.0 to 1.0).
20+
The split fractions should sum to 1.0.
21+
rates (list[float] | None): The flow rates for each output stream.
1522
1623
Returns:
1724
list[FluidStream]: A list containing the resulting FluidStreams.
1825
"""
26+
if (split_fractions is None) == (rates is None):
27+
raise IllegalStateException("Either split_fractions or rates must be provided.")
28+
if rates is not None:
29+
split_fractions = self.convert_rates_to_split_fractions(rates)
30+
1931
# make sure number of split fractions matches number of outputs
32+
assert split_fractions is not None
2033
if len(split_fractions) != self.number_of_outputs:
2134
raise ValueError("Number of split fractions must match number of outputs.")
2235

23-
# normalize split fractions
24-
total = sum(split_fractions)
25-
normalized_fractions = [f / total for f in split_fractions]
36+
# make sure split fractions sum to 1.0
37+
total_fraction = sum(split_fractions)
38+
if total_fraction != 1.0:
39+
raise IllegalStateException("Split fractions must sum to 1.0.")
2640

2741
return [
2842
FluidStream(
2943
thermo_system=stream.thermo_system,
3044
mass_rate_kg_per_h=stream.mass_rate_kg_per_h * split_fraction,
3145
)
32-
for split_fraction in normalized_fractions
46+
for split_fraction in split_fractions
3347
]
48+
49+
@staticmethod
50+
def convert_rates_to_split_fractions(rates: list[float]) -> list[float]:
51+
"""
52+
Converts a list of flow rates to split fractions. Some of the flow rates may be very small negative
53+
numbers due to floating point precision issues (conversion between standard rate and mass rate and back),
54+
these are corrected to zero if they are less than .
55+
56+
Args:
57+
rates (list[float]): The flow rates for each output stream.
58+
59+
Returns:
60+
list[float]: The corresponding split fractions.
61+
"""
62+
if any(rate < -FLOATING_POINT_PRECISION for rate in rates):
63+
raise IllegalStateException(
64+
f"Negative rate found when splitting stream in compressor stage splitter. "
65+
f"Rates: {rates}. Correcting negative rate to zero."
66+
)
67+
elif any(-FLOATING_POINT_PRECISION < rate < 0 for rate in rates):
68+
logger.warning(
69+
f"Negative rate found when splitting stream in compressor stage splitter. "
70+
f"Rates before correction: {rates}. Correcting negative rate to zero."
71+
)
72+
rates = [max(rate, 0.0) for rate in rates]
73+
74+
return [rate / sum(rates) for rate in rates]

0 commit comments

Comments
 (0)