Skip to content

Commit 98d1656

Browse files
committed
refactor: make thermosystem use fluid_model object
1 parent f280fc2 commit 98d1656

6 files changed

Lines changed: 56 additions & 53 deletions

File tree

src/libecalc/domain/process/value_objects/fluid_stream/mixing.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
IncompatibleThermoSystemProvidersException,
1111
ZeroTotalMassRateException,
1212
)
13-
from libecalc.domain.process.value_objects.fluid_stream.fluid_model import FluidComposition
13+
from libecalc.domain.process.value_objects.fluid_stream.fluid_model import FluidComposition, FluidModel
1414
from libecalc.domain.process.value_objects.fluid_stream.fluid_stream import FluidStream
1515
from libecalc.domain.process.value_objects.fluid_stream.process_conditions import ProcessConditions
1616

@@ -105,12 +105,14 @@ def mix_streams(self, streams: list[FluidStream]) -> FluidStream:
105105
)
106106

107107
# Create a new thermo system using the same type as the first stream
108-
# Note: this assumes the thermo system provider supports initialization with composition, EoS model, and conditions
109-
# TODO: use a factory method on the thermo system provider to create with the correct args
108+
# Note: this assumes the thermo system provider supports initialization with FluidModel and conditions
110109
first_stream_thermo = streams[0].thermo_system
111-
thermo_system_mix = first_stream_thermo.__class__( # type: ignore[call-arg]
110+
mix_fluid_model = FluidModel(
112111
composition=mix_composition,
113112
eos_model=reference_eos_model,
113+
)
114+
thermo_system_mix = first_stream_thermo.__class__( # type: ignore[call-arg]
115+
fluid_model=mix_fluid_model,
114116
conditions=conditions,
115117
)
116118

src/libecalc/infrastructure/neqsim_fluid_provider/neqsim_fluid_factory.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,7 @@ def create_thermo_system(self, pressure_bara: float, temperature_kelvin: float)
4949
temperature_kelvin=temperature_kelvin,
5050
)
5151
return NeqSimThermoSystem(
52-
composition=self._fluid_model.composition,
53-
eos_model=self._fluid_model.eos_model,
52+
fluid_model=self._fluid_model,
5453
conditions=conditions,
5554
)
5655

src/libecalc/infrastructure/neqsim_fluid_provider/neqsim_thermo_system.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from functools import cached_property
44

55
from ecalc_neqsim_wrapper.thermo import NeqsimFluid
6-
from libecalc.domain.process.value_objects.fluid_stream.fluid_model import EoSModel, FluidComposition
6+
from libecalc.domain.process.value_objects.fluid_stream.fluid_model import EoSModel, FluidComposition, FluidModel
77
from libecalc.domain.process.value_objects.fluid_stream.process_conditions import ProcessConditions
88
from libecalc.domain.process.value_objects.fluid_stream.thermo_system import ThermoSystemInterface
99

@@ -17,14 +17,13 @@ class NeqSimThermoSystem(ThermoSystemInterface):
1717

1818
def __init__(
1919
self,
20-
composition: FluidComposition,
21-
eos_model: EoSModel,
20+
fluid_model: FluidModel,
2221
conditions: ProcessConditions,
2322
neqsim_fluid: NeqsimFluid | None = None,
2423
):
2524
# Normalize composition to ensure it sums to 1
26-
self._composition = composition.normalized()
27-
self._eos_model = eos_model
25+
self._composition = fluid_model.composition.normalized()
26+
self._eos_model = fluid_model.eos_model
2827
self._conditions = conditions
2928

3029
if neqsim_fluid is not None:
@@ -122,9 +121,14 @@ def flash_to_conditions(self, conditions: ProcessConditions, remove_liquid: bool
122121
# Get updated composition if liquid is removed, otherwise keep the original
123122
composition = updated_fluid.composition if remove_liquid else self._composition
124123

125-
return NeqSimThermoSystem(
124+
# Create a new fluid model with the updated composition
125+
updated_fluid_model = FluidModel(
126126
composition=composition,
127127
eos_model=self._eos_model,
128+
)
129+
130+
return NeqSimThermoSystem(
131+
fluid_model=updated_fluid_model,
128132
conditions=conditions,
129133
neqsim_fluid=updated_fluid,
130134
)
@@ -160,9 +164,14 @@ def flash_to_pressure_and_enthalpy_change(
160164
temperature_kelvin=updated_fluid.temperature_kelvin,
161165
)
162166

163-
return NeqSimThermoSystem(
167+
# Create a new fluid model with the updated composition
168+
updated_fluid_model = FluidModel(
164169
composition=composition,
165170
eos_model=self._eos_model,
171+
)
172+
173+
return NeqSimThermoSystem(
174+
fluid_model=updated_fluid_model,
166175
conditions=new_conditions,
167176
neqsim_fluid=updated_fluid,
168177
)

tests/libecalc/domain/process/conftest.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import pytest
22

3-
from libecalc.domain.process.value_objects.fluid_stream.fluid_model import EoSModel, FluidComposition
3+
from libecalc.domain.process.value_objects.fluid_stream.fluid_model import EoSModel, FluidComposition, FluidModel
44
from libecalc.domain.process.value_objects.fluid_stream.fluid_stream import FluidStream
55
from libecalc.domain.process.value_objects.fluid_stream.process_conditions import ProcessConditions
66
from libecalc.domain.process.value_objects.fluid_stream.thermo_system import ThermoSystemInterface
@@ -47,13 +47,12 @@ class MockThermoSystem(ThermoSystemInterface):
4747

4848
def __init__(
4949
self,
50-
composition: FluidComposition | None = None,
51-
eos_model: EoSModel = EoSModel.SRK,
52-
conditions: ProcessConditions | None = None,
50+
fluid_model: FluidModel,
51+
conditions: ProcessConditions,
5352
):
54-
self._composition = composition or FluidComposition(methane=1.0) # Default simple composition
55-
self._eos_model = eos_model
56-
self._conditions = conditions or ProcessConditions(pressure_bara=20.0, temperature_kelvin=310.0)
53+
self._composition = fluid_model.composition
54+
self._eos_model = fluid_model.eos_model
55+
self._conditions = conditions
5756

5857
@property
5958
def composition(self) -> FluidComposition:
@@ -104,21 +103,24 @@ def vapor_fraction_molar(self) -> float:
104103
return 1.0 # Mock value
105104

106105
def flash_to_conditions(self, conditions: ProcessConditions, remove_liquid: bool = True):
107-
return MockThermoSystem(self._composition, self._eos_model, conditions)
106+
fluid_model = FluidModel(composition=self._composition, eos_model=self._eos_model)
107+
return MockThermoSystem(fluid_model, conditions)
108108

109109
def flash_to_pressure_and_enthalpy_change(
110110
self, pressure_bara: float, enthalpy_change: float, remove_liquid: bool = True
111111
):
112112
new_temp = self.temperature_kelvin + (enthalpy_change / 1000.0)
113113
new_conditions = ProcessConditions(pressure_bara=pressure_bara, temperature_kelvin=new_temp)
114-
return MockThermoSystem(self._composition, self._eos_model, new_conditions)
114+
fluid_model = FluidModel(composition=self._composition, eos_model=self._eos_model)
115+
return MockThermoSystem(fluid_model, new_conditions)
115116

116117

117118
@pytest.fixture
118119
def mock_thermo_system(medium_composition) -> MockThermoSystem:
119120
"""Create a mock thermo system for testing."""
120121
conditions = ProcessConditions(pressure_bara=20.0, temperature_kelvin=310.0)
121-
return MockThermoSystem(composition=medium_composition, eos_model=EoSModel.SRK, conditions=conditions)
122+
fluid_model = FluidModel(composition=medium_composition, eos_model=EoSModel.SRK)
123+
return MockThermoSystem(fluid_model, conditions)
122124

123125

124126
@pytest.fixture
@@ -127,7 +129,8 @@ def mock_thermo_system_factory(medium_composition):
127129

128130
def factory(pressure_bara: float, temperature_kelvin: float):
129131
conditions = ProcessConditions(pressure_bara=pressure_bara, temperature_kelvin=temperature_kelvin)
130-
return MockThermoSystem(composition=medium_composition, eos_model=EoSModel.SRK, conditions=conditions)
132+
fluid_model = FluidModel(composition=medium_composition, eos_model=EoSModel.SRK)
133+
return MockThermoSystem(fluid_model, conditions)
131134

132135
return factory
133136

tests/libecalc/domain/process/fluid_stream/test_mixing.py

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
IncompatibleEoSModelsException,
55
IncompatibleThermoSystemProvidersException,
66
)
7-
from libecalc.domain.process.value_objects.fluid_stream.fluid_model import EoSModel
7+
from libecalc.domain.process.value_objects.fluid_stream.fluid_model import EoSModel, FluidModel
88
from libecalc.domain.process.value_objects.fluid_stream.fluid_stream import FluidStream
99
from libecalc.domain.process.value_objects.fluid_stream.mixing import SimplifiedStreamMixing
1010
from libecalc.domain.process.value_objects.fluid_stream.process_conditions import ProcessConditions
@@ -26,13 +26,11 @@ def test_mix_medium_and_ultra_rich_compositions(self, medium_composition, ultra_
2626
# Create thermo systems
2727
conditions = ProcessConditions(pressure_bara=pressure, temperature_kelvin=temperature)
2828
medium_thermo = NeqSimThermoSystem(
29-
composition=medium_composition,
30-
eos_model=eos_model,
29+
fluid_model=FluidModel(composition=medium_composition, eos_model=eos_model),
3130
conditions=conditions,
3231
)
3332
ultra_rich_thermo = NeqSimThermoSystem(
34-
composition=ultra_rich_composition,
35-
eos_model=eos_model,
33+
fluid_model=FluidModel(composition=ultra_rich_composition, eos_model=eos_model),
3634
conditions=conditions,
3735
)
3836

@@ -72,15 +70,13 @@ def test_mix_streams_with_different_conditions(self, medium_composition):
7270
# Create thermo systems
7371
conditions1 = ProcessConditions(pressure_bara=20.0, temperature_kelvin=300.0)
7472
thermo1 = NeqSimThermoSystem(
75-
composition=medium_composition,
76-
eos_model=eos_model,
73+
fluid_model=FluidModel(composition=medium_composition, eos_model=eos_model),
7774
conditions=conditions1,
7875
)
7976

8077
conditions2 = ProcessConditions(pressure_bara=10.0, temperature_kelvin=350.0)
8178
thermo2 = NeqSimThermoSystem(
82-
composition=medium_composition,
83-
eos_model=eos_model,
79+
fluid_model=FluidModel(composition=medium_composition, eos_model=eos_model),
8480
conditions=conditions2,
8581
)
8682

@@ -107,13 +103,11 @@ def test_mix_streams_with_different_eos_models(self, medium_composition):
107103
# Create thermo systems with different EoS models
108104
conditions = ProcessConditions(pressure_bara=15.0, temperature_kelvin=300.0)
109105
thermo1 = NeqSimThermoSystem(
110-
composition=medium_composition,
111-
eos_model=EoSModel.SRK,
106+
fluid_model=FluidModel(composition=medium_composition, eos_model=EoSModel.SRK),
112107
conditions=conditions,
113108
)
114109
thermo2 = NeqSimThermoSystem(
115-
composition=medium_composition,
116-
eos_model=EoSModel.PR,
110+
fluid_model=FluidModel(composition=medium_composition, eos_model=EoSModel.PR),
117111
conditions=conditions,
118112
)
119113

@@ -133,8 +127,7 @@ def test_mix_streams_with_different_thermo_system_providers(self, medium_composi
133127

134128
# Create one stream with NeqSimThermoSystem
135129
neqsim_thermo = NeqSimThermoSystem(
136-
composition=medium_composition,
137-
eos_model=eos_model,
130+
fluid_model=FluidModel(composition=medium_composition, eos_model=eos_model),
138131
conditions=conditions,
139132
)
140133
neqsim_stream = FluidStream(thermo_system=neqsim_thermo, mass_rate_kg_per_h=500.0)

tests/libecalc/domain/process/fluid_stream/test_thermo_system.py

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import pytest
44

55
from ecalc_neqsim_wrapper.thermo import NeqsimFluid
6-
from libecalc.domain.process.value_objects.fluid_stream.fluid_model import EoSModel
6+
from libecalc.domain.process.value_objects.fluid_stream.fluid_model import EoSModel, FluidModel
77
from libecalc.domain.process.value_objects.fluid_stream.process_conditions import ProcessConditions
88
from libecalc.infrastructure.neqsim_fluid_provider.neqsim_thermo_system import NeqSimThermoSystem
99

@@ -15,9 +15,8 @@ def test_initialization_creates_neqsim_fluid(self, medium_composition):
1515
"""Test that initialization creates a NeqsimFluid object internally."""
1616
with patch.object(NeqsimFluid, "create_thermo_system", return_value=Mock()) as mock_create:
1717
conditions = ProcessConditions(pressure_bara=10.0, temperature_kelvin=300.0)
18-
thermo_system = NeqSimThermoSystem(
19-
composition=medium_composition, eos_model=EoSModel.SRK, conditions=conditions
20-
)
18+
fluid_model = FluidModel(composition=medium_composition, eos_model=EoSModel.SRK)
19+
thermo_system = NeqSimThermoSystem(fluid_model=fluid_model, conditions=conditions)
2120

2221
# Check NeqsimFluid.create_thermo_system was called with correct arguments
2322
# Note: composition is normalized before being passed to create_thermo_system
@@ -38,11 +37,10 @@ def test_initialization_with_neqsim_fluid(self, medium_composition):
3837
"""Test initialization with a provided NeqsimFluid object."""
3938
mock_fluid = Mock()
4039
conditions = ProcessConditions(pressure_bara=10.0, temperature_kelvin=300.0)
40+
fluid_model = FluidModel(composition=medium_composition, eos_model=EoSModel.SRK)
4141

4242
with patch.object(NeqsimFluid, "create_thermo_system", return_value=Mock()) as mock_create:
43-
thermo_system = NeqSimThermoSystem(
44-
composition=medium_composition, eos_model=EoSModel.SRK, conditions=conditions, neqsim_fluid=mock_fluid
45-
)
43+
thermo_system = NeqSimThermoSystem(fluid_model=fluid_model, conditions=conditions, neqsim_fluid=mock_fluid)
4644

4745
# Check that create_thermo_system was not called
4846
mock_create.assert_not_called()
@@ -54,7 +52,7 @@ def test_immutability(self, medium_composition):
5452
"""Test that NeqSimThermoSystem attributes are effectively immutable."""
5553
conditions = ProcessConditions(pressure_bara=10.0, temperature_kelvin=300.0)
5654
thermo_system = NeqSimThermoSystem(
57-
composition=medium_composition, eos_model=EoSModel.SRK, conditions=conditions
55+
fluid_model=FluidModel(composition=medium_composition, eos_model=EoSModel.SRK), conditions=conditions
5856
)
5957

6058
# Attempting to modify public property attributes should raise an exception
@@ -102,7 +100,7 @@ def test_properties_cache(self, medium_composition):
102100
# Create the thermo system
103101
conditions = ProcessConditions(pressure_bara=10.0, temperature_kelvin=300.0)
104102
thermo_system = NeqSimThermoSystem(
105-
composition=medium_composition, eos_model=EoSModel.SRK, conditions=conditions
103+
fluid_model=FluidModel(composition=medium_composition, eos_model=EoSModel.SRK), conditions=conditions
106104
)
107105

108106
# Access properties multiple times - should only compute once
@@ -136,7 +134,8 @@ def test_flash_to_conditions(self, medium_composition):
136134
# Create the original thermo system
137135
original_conditions = ProcessConditions(pressure_bara=10.0, temperature_kelvin=300.0)
138136
original_thermo = NeqSimThermoSystem(
139-
composition=medium_composition, eos_model=EoSModel.SRK, conditions=original_conditions
137+
fluid_model=FluidModel(composition=medium_composition, eos_model=EoSModel.SRK),
138+
conditions=original_conditions,
140139
)
141140

142141
# Test with remove_liquid=False to preserve composition
@@ -170,8 +169,7 @@ def test_integration_properties_at_conditions(self, medium_composition):
170169
temperature = 400.0
171170
conditions = ProcessConditions(pressure_bara=pressure, temperature_kelvin=temperature)
172171
thermo_system = NeqSimThermoSystem(
173-
composition=medium_composition,
174-
eos_model=EoSModel.SRK,
172+
fluid_model=FluidModel(composition=medium_composition, eos_model=EoSModel.SRK),
175173
conditions=conditions,
176174
)
177175

@@ -191,8 +189,7 @@ def test_direct_vs_property_access(self, medium_composition):
191189
temperature = 400.0
192190
conditions = ProcessConditions(pressure_bara=pressure, temperature_kelvin=temperature)
193191
thermo_system = NeqSimThermoSystem(
194-
composition=medium_composition,
195-
eos_model=EoSModel.SRK,
192+
fluid_model=FluidModel(composition=medium_composition, eos_model=EoSModel.SRK),
196193
conditions=conditions,
197194
)
198195

0 commit comments

Comments
 (0)