Skip to content

Commit

Permalink
begin fixing tests
Browse files Browse the repository at this point in the history
  • Loading branch information
yoelcortes committed Sep 18, 2024
1 parent 6bb2a07 commit f837b67
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 202 deletions.
20 changes: 5 additions & 15 deletions tests/test_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,24 +31,14 @@ def test_registration_alias():

def test_vlle():
tmo.settings.set_thermo(['Water', 'Ethanol', 'Octane'], cache=True)
s = tmo.Stream(None, Water=1, Ethanol=1, Octane=2, vlle=True, T=351)
assert_allclose(s.mol, [1, 1, 2]) # mass balance
s = tmo.Stream(None, Water=1, Ethanol=0.5, Octane=2, vlle=True, T=350)
assert_allclose(s.mol, [1, 0.5, 2]) # mass balance
total = s.F_mol
xl = s.imol['l'].sum() / total
xL = s.imol['L'].sum() / total
xg = s.imol['g'].sum() / total
assert_allclose(xl + xL, 0.533447771190868, atol=0.05) # Convergence
assert_allclose(xg, 0.46655222880913216, atol=0.05)
# Make sure past equilibrium conditions do not affect result of vlle
s = tmo.Stream(None, Water=1, Ethanol=1, Octane=2, T=351)
s.vle(T=351, P=101325)
s.vlle(T=351, P=101325)
assert_allclose(s.mol, [1, 1, 2]) # mass balance
xl = s.imol['l'].sum() / total
xL = s.imol['L'].sum() / total
xL = s.imol['L'].sum() / total if 'L' in s.phases else 0.
xg = s.imol['g'].sum() / total
assert_allclose(xl + xL, 0.533447771190868, atol=0.05) # Convergence
assert_allclose(xg, 0.46655222880913216, atol=0.05)
assert_allclose(xl + xL, 0.802404472833999, atol=0.05) # Convergence
assert_allclose(xg, 0.19759552716600104, atol=0.05)

s = tmo.Stream(None, Water=1, Ethanol=1, Octane=2, vlle=True, T=300)
assert set(s.phases) == set(['l', 'L']) # No gas phase
Expand Down
42 changes: 19 additions & 23 deletions thermosteam/_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -2058,37 +2058,33 @@ def vlle(self, T, P):
lle = eq.LLE(imol,
self._thermal_condition,
self._thermo)
data = imol.data
net_chemical_flows = data.sum(axis=0)
data.clear()
imol['l'] = net_chemical_flows
total_flow = net_chemical_flows.sum()
data = self._imol.data
LIQ, gas, liq = data
liq += LIQ # All flows must be in the 'l' phase for VLE
LIQ[:] = 0.
vle(T=T, P=P)
if not gas.any() or not liq.any(): return
lle(T, P)
if not (LIQ.any() and liq.any()): return
total_flow = data.sum()
def f(x, done=[False]):
if done[0]: return x
data[:] = x
lle(T=T, P=P)
net_phase_flows = data.sum(axis=1, keepdims=True)
compositions = data / net_phase_flows
if (abs(compositions[0] - compositions[2]).sum() < 1e-3
or compositions[0].sum() < 1e-6
or compositions[2].sum() < 1e-6): # Perform VLE on one liquid phase
data[2] += data[0] # All flows must be in the 'l' phase for VLE
data[0] = 0.
vle(T=T, P=P)
done[0] = True
return data
else: # Perform VLE on each liquid phase
vle(T=T, P=P)
no_vapor = not data[1].any()
data[2], data[0] = data[0].copy(), data[2].copy()
vle(T=T, P=P)
done[0] = no_vapor and not data[1].any() # No VLE
vle(T=T, P=P)
liq[:], LIQ[:] = LIQ, liq.copy()
vle(T=T, P=P)
liq[:], LIQ[:] = LIQ, liq.copy()
return data.to_array()
data[:] = total_flow * flx.fixed_point(
f, data / total_flow, xtol=1e-3,
flx.fixed_point(
f, data / total_flow, xtol=1e-6,
checkiter=False, checkconvergence=False,
convergenceiter=10
)
if np.abs(liq - LIQ).sum() < 1e-6:
liq += LIQ
LIQ.clear()
data *= total_flow

@property
def vle_chemicals(self) -> list[tmo.Chemical]:
Expand Down
4 changes: 3 additions & 1 deletion thermosteam/equilibrium/dew_point.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ def gamma_iter(gamma, x_gamma, T, P, f_gamma, gamma_args):
return f_gamma(x, T, *gamma_args)

def solve_x(x_guess, x_gamma, T, P, f_gamma, gamma_args):
mask = x_guess < 1e-32
x_guess[mask] = 1e-32
x_guess = fn.normalize(x_guess)
gamma = f_gamma(x_guess, T, *gamma_args)
args = (x_gamma, T, P, f_gamma, gamma_args)
gamma = flx.wegstein(
Expand Down Expand Up @@ -339,7 +342,6 @@ def solve_Px(self, z, T, gas_conversion=None):
P_guess, x = self._Px_ideal(z_over_Psats)
args = (T, z_norm, z_over_Psats, Psats, x)
f = self._P_error
breakpoint()
try:
P = flx.aitken_secant(f, P_guess, P_guess-10, self.P_tol, 5e-12, args,
checkiter=False, maxiter=self.maxiter)
Expand Down
4 changes: 2 additions & 2 deletions thermosteam/equilibrium/lle.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ class LLE(Equilibrium, phases='lL'):
>>> lle(T=360, top_chemical='Octane')
>>> lle
LLE(imol=MolarFlowIndexer(
L=[('Water', 2.67), ('Ethanol', 2.28), ('Octane', 39.9), ('Hexane', 0.988)],
l=[('Water', 301.), ('Ethanol', 27.7), ('Octane', 0.0788), ('Hexane', 0.0115)]),
L=[('Water', 2.552), ('Ethanol', 2.167), ('Octane', 39.92), ('Hexane', 0.9886)],
l=[('Water', 301.4), ('Ethanol', 27.83), ('Octane', 0.07738), ('Hexane', 0.01141)]),
thermal_condition=ThermalCondition(T=360.00, P=101325))
References
Expand Down
150 changes: 0 additions & 150 deletions thermosteam/equilibrium/vlle.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,157 +165,7 @@ class VLLE(Equilibrium, phases='lLg'):
Themodynamic property package for equilibrium calculations.
Defaults to `thermosteam.settings.get_thermo()`.
Examples
--------
First create a VLLE object:
>>> from thermosteam import indexer, equilibrium, settings
>>> settings.set_thermo(['Water', 'Ethanol', 'Methanol', 'Propanol'], cache=True)
>>> imol = indexer.MolarFlowIndexer(
... l=[('Water', 304), ('Ethanol', 30)],
... g=[('Methanol', 40), ('Propanol', 1)])
>>> vlle = equilibrium.VLLE(imol)
>>> vlle
VLLE(imol=MolarFlowIndexer(
g=[('Methanol', 40), ('Propanol', 1)],
l=[('Water', 304), ('Ethanol', 30)]),
thermal_condition=ThermalCondition(T=298.15, P=101325))
Equilibrium given vapor fraction and pressure:
>>> vlle(V=0.5, P=101325)
>>> vlle
VLLE(imol=MolarFlowIndexer(
g=[('Water', 126.7), ('Ethanol', 26.38), ('Methanol', 33.49), ('Propanol', 0.8958)],
l=[('Water', 177.3), ('Ethanol', 3.622), ('Methanol', 6.509), ('Propanol', 0.1042)]),
thermal_condition=ThermalCondition(T=363.85, P=101325))
Equilibrium given temperature and pressure:
>>> vlle(T=363.88, P=101325)
>>> vlle
VLLE(imol=MolarFlowIndexer(
g=[('Water', 127.4), ('Ethanol', 26.41), ('Methanol', 33.54), ('Propanol', 0.8968)],
l=[('Water', 176.6), ('Ethanol', 3.59), ('Methanol', 6.456), ('Propanol', 0.1032)]),
thermal_condition=ThermalCondition(T=363.88, P=101325))
Equilibrium given enthalpy and pressure:
>>> H = vlle.thermo.mixture.xH(vlle.imol, T=363.88, P=101325)
>>> vlle(H=H, P=101325)
>>> vlle
VLLE(imol=MolarFlowIndexer(
g=[('Water', 127.4), ('Ethanol', 26.41), ('Methanol', 33.54), ('Propanol', 0.8968)],
l=[('Water', 176.6), ('Ethanol', 3.59), ('Methanol', 6.456), ('Propanol', 0.1032)]),
thermal_condition=ThermalCondition(T=363.88, P=101325))
Equilibrium given entropy and pressure:
>>> S = vlle.thermo.mixture.xS(vlle.imol, T=363.88, P=101325)
>>> vlle(S=S, P=101325)
>>> vlle
VLLE(imol=MolarFlowIndexer(
g=[('Water', 127.4), ('Ethanol', 26.41), ('Methanol', 33.54), ('Propanol', 0.8968)],
l=[('Water', 176.6), ('Ethanol', 3.59), ('Methanol', 6.456), ('Propanol', 0.1032)]),
thermal_condition=ThermalCondition(T=363.88, P=101325))
Equilibrium given vapor fraction and temperature:
>>> vlle(V=0.5, T=363.88)
>>> vlle
VLLE(imol=MolarFlowIndexer(
g=[('Water', 126.7), ('Ethanol', 26.38), ('Methanol', 33.49), ('Propanol', 0.8958)],
l=[('Water', 177.3), ('Ethanol', 3.622), ('Methanol', 6.509), ('Propanol', 0.1042)]),
thermal_condition=ThermalCondition(T=363.88, P=101431))
Equilibrium given enthalpy and temperature:
>>> vlle(H=H, T=363.88)
>>> vlle
VLLE(imol=MolarFlowIndexer(
g=[('Water', 127.4), ('Ethanol', 26.41), ('Methanol', 33.54), ('Propanol', 0.8968)],
l=[('Water', 176.6), ('Ethanol', 3.59), ('Methanol', 6.456), ('Propanol', 0.1032)]),
thermal_condition=ThermalCondition(T=363.88, P=101325))
Non-partitioning heavy and gaseous chemicals also affect VLLE. Calculation
are repeated with non-partitioning chemicals:
>>> from thermosteam import indexer, equilibrium, settings, Chemical
>>> O2 = Chemical('O2', phase='g')
>>> Glucose = Chemical('Glucose', phase='l', default=True)
>>> settings.set_thermo(['Water', 'Ethanol', 'Methanol', 'Propanol', O2, Glucose], cache=True)
>>> imol = indexer.MolarFlowIndexer(
... l=[('Water', 304), ('Ethanol', 30), ('Glucose', 5)],
... g=[('Methanol', 40), ('Propanol', 1), ('O2', 10)])
>>> vlle = equilibrium.VLLE(imol)
>>> vlle(T=363.88, P=101325)
>>> vlle
VLLE(imol=MolarFlowIndexer(
g=[('Water', 159.5), ('Ethanol', 27.65), ('Methanol', 35.63), ('Propanol', 0.9337), ('O2', 10)],
l=[('Water', 144.5), ('Ethanol', 2.352), ('Methanol', 4.369), ('Propanol', 0.0663), ('Glucose', 5)]),
thermal_condition=ThermalCondition(T=363.88, P=101325))
>>> vlle(V=0.5, P=101325)
>>> vlle
VLLE(imol=MolarFlowIndexer(
g=[('Water', 126.7), ('Ethanol', 26.38), ('Methanol', 33.52), ('Propanol', 0.8957), ('O2', 10)],
l=[('Water', 177.3), ('Ethanol', 3.618), ('Methanol', 6.478), ('Propanol', 0.1043), ('Glucose', 5)]),
thermal_condition=ThermalCondition(T=362.47, P=101325))
>>> H = vlle.thermo.mixture.xH(vlle.imol, T=363.88, P=101325)
>>> vlle(H=H, P=101325)
>>> vlle
VLLE(imol=MolarFlowIndexer(
g=[('Water', 127.4), ('Ethanol', 26.42), ('Methanol', 33.58), ('Propanol', 0.8968), ('O2', 10)],
l=[('Water', 176.6), ('Ethanol', 3.583), ('Methanol', 6.421), ('Propanol', 0.1032), ('Glucose', 5)]),
thermal_condition=ThermalCondition(T=362.51, P=101325))
>>> S = vlle.thermo.mixture.xS(vlle.imol, T=363.88, P=101325)
>>> vlle(S=S, P=101325)
>>> vlle
VLLE(imol=MolarFlowIndexer(
g=[('Water', 128.2), ('Ethanol', 26.45), ('Methanol', 33.63), ('Propanol', 0.8979), ('O2', 10)],
l=[('Water', 175.8), ('Ethanol', 3.548), ('Methanol', 6.365), ('Propanol', 0.1021), ('Glucose', 5)]),
thermal_condition=ThermalCondition(T=362.54, P=101325))
>>> vlle(V=0.5, T=363.88)
>>> vlle
VLLE(imol=MolarFlowIndexer(
g=[('Water', 126.7), ('Ethanol', 26.38), ('Methanol', 33.49), ('Propanol', 0.8958), ('O2', 10)],
l=[('Water', 177.3), ('Ethanol', 3.622), ('Methanol', 6.509), ('Propanol', 0.1042), ('Glucose', 5)]),
thermal_condition=ThermalCondition(T=363.88, P=106841))
>>> vlle(H=H, T=363.88)
>>> vlle
VLLE(imol=MolarFlowIndexer(
g=[('Water', 126.7), ('Ethanol', 26.38), ('Methanol', 33.49), ('Propanol', 0.8958), ('O2', 10)],
l=[('Water', 177.3), ('Ethanol', 3.622), ('Methanol', 6.51), ('Propanol', 0.1042), ('Glucose', 5)]),
thermal_condition=ThermalCondition(T=363.88, P=106842))
>>> vlle(S=S, T=363.88)
>>> vlle
VLLE(imol=MolarFlowIndexer(
g=[('Water', 128.1), ('Ethanol', 26.45), ('Methanol', 33.6), ('Propanol', 0.8978), ('O2', 10)],
l=[('Water', 175.9), ('Ethanol', 3.555), ('Methanol', 6.399), ('Propanol', 0.1022), ('Glucose', 5)]),
thermal_condition=ThermalCondition(T=363.88, P=106562))
The presence of a non-partitioning gaseous chemical will result in some
evaporation, even if the tempeture is below the saturated bubble point:
>>> from thermosteam import indexer, equilibrium, settings, Chemical
>>> O2 = Chemical('O2', phase='g')
>>> settings.set_thermo(['Water', O2], cache=True)
>>> imol = indexer.MolarFlowIndexer(
... l=[('Water', 30)],
... g=[('O2', 10)])
>>> vlle = equilibrium.VLLE(imol)
>>> vlle(T=300., P=101325)
>>> vlle
VLLE(imol=MolarFlowIndexer(
g=[('Water', 0.3617), ('O2', 10)],
l=[('Water', 29.64)]),
thermal_condition=ThermalCondition(T=300.00, P=101325))
"""
__slots__ = (
'vle',
Expand Down
22 changes: 11 additions & 11 deletions thermosteam/separations.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ def lle_partition_coefficients(top, bottom):
>>> IDs
('Water', 'Ethanol', 'Octanol')
>>> round(K[2], -1) # Octanol
3330.0
2390.0
"""
IDs = tuple([i.ID for i in bottom.lle_chemicals])
Expand Down Expand Up @@ -605,15 +605,15 @@ def lle(feed, top, bottom, top_chemical=None, efficiency=1.0, multi_stream=None)
>>> top.show()
Stream: top
phase: 'l', T: 298.15 K, P: 101325 Pa
flow (kmol/hr): Water 3.55
Ethanol 0.861
flow (kmol/hr): Water 2.87
Ethanol 0.828
Octanol 20
>>> bottom.show()
Stream: bottom
phase: 'l', T: 298.15 K, P: 101325 Pa
flow (kmol/hr): Water 16.5
Ethanol 0.139
Octanol 0.00409
flow (kmol/hr): Water 17.1
Ethanol 0.172
Octanol 0.00612
Assume that 1% of the feed is not in equilibrium (possibly due to poor mixing):
Expand All @@ -627,12 +627,12 @@ def lle(feed, top, bottom, top_chemical=None, efficiency=1.0, multi_stream=None)
>>> ms.show()
MultiStream: ms
phases: ('L', 'l'), T: 298.15 K, P: 101325 Pa
flow (kmol/hr): (L) Water 3.55
Ethanol 0.861
flow (kmol/hr): (L) Water 2.87
Ethanol 0.828
Octanol 20
(l) Water 16.5
Ethanol 0.139
Octanol 0.00409
(l) Water 17.1
Ethanol 0.172
Octanol 0.00612
"""
if multi_stream:
Expand Down

0 comments on commit f837b67

Please sign in to comment.