@@ -39,22 +39,51 @@ def solve_y(y_phi, phi, T, P, y_guess):
3939# %% Bubble point values container
4040
4141class BubblePointValues :
42- __slots__ = ('T' , 'P' , 'IDs' , 'z' , 'y' )
42+ __slots__ = ('T' , 'P' , 'IDs' , 'z' , 'y' , 'α' )
4343
44- def __init__ (self , T , P , IDs , z , y ):
44+ def __init__ (self , T , P , IDs , z , y , α = None ):
4545 self .T = T
4646 self .P = P
4747 self .IDs = IDs
4848 self .z = z
4949 self .y = y
50-
50+ self .α = α
51+
5152 @property
5253 def x (self ): return self .z
5354
5455 @property
5556 def K (self ):
5657 return self .y / self .x
5758
59+ @property
60+ def xα (self ):
61+ return self .α / self .α .sum ()
62+
63+ @property
64+ def xβ (self ):
65+ return self .β / self .β .sum ()
66+
67+ @property
68+ def β (self ):
69+ return self .z - self .α
70+
71+ @property
72+ def ϕ (self ):
73+ return self .α .sum ()
74+
75+ @property
76+ def KL (self ):
77+ return self .xα / self .xβ
78+
79+ @property
80+ def Kα (self ):
81+ return self .y / self .xα
82+
83+ @property
84+ def Kβ (self ):
85+ return self .y / self .xβ
86+
5887 def __repr__ (self ):
5988 return f"{ type (self ).__name__ } (T={ self .T :.2f} , P={ self .P :.0f} , IDs={ self .IDs } , z={ self .z } , y={ self .y } )"
6089
@@ -157,11 +186,14 @@ def _T_error(self, T, P, z_over_P, z_norm, y):
157186 y [:] = solve_y (y_phi , self .phi , T , P , y )
158187 return 1. - y .sum ()
159188
160- def _T_error_lle (self , T , P , z , y , x ):
189+ def _T_error_lle (self , T , P , z , y , x , α ):
161190 if T <= 0 : raise InfeasibleRegion ('negative temperature' )
162191 Psats = np .array ([i (T ) for i in self .Psats ], dtype = float )
163- mol = solve_lle_mol (self .gamma , z , T , P , sample = x )
164- x [:] = mol / mol .sum () if mol .any () else z
192+ α [:] = solve_lle_mol (self .gamma , z , T , P , sample = x )
193+ if α .any ():
194+ x [:] = α / α .sum ()
195+ else :
196+ x = z
165197 y_phi = (x / P
166198 * Psats
167199 * self .gamma (x , T , P )
@@ -181,10 +213,13 @@ def _P_error_dep(self, P, T, z, Psats, z_Psats, y):
181213 y [:] = solve_y (y_phi , self .phi , T , P , y )
182214 return 1. - y .sum ()
183215
184- def _P_error_lle (self , P , T , z , Psats , y , x ):
216+ def _P_error_lle (self , P , T , z , Psats , y , x , α ):
185217 if P <= 0 : raise InfeasibleRegion ('negative pressure' )
186- mol = solve_lle_mol (self .gamma , z , T , P , sample = x )
187- x [:] = mol / mol .sum () if mol .any () else z
218+ α [:] = solve_lle_mol (self .gamma , z , T , P , sample = x )
219+ if α .any ():
220+ x [:] = α / α .sum ()
221+ else :
222+ x = z
188223 y_phi = Psats * x * self .gamma (x , T , P ) * self .pcf (T , P , Psats ) / P
189224 y [:] = solve_y (y_phi , self .phi , T , P , y )
190225 return 1. - y .sum ()
@@ -242,17 +277,17 @@ def __call__(self, z, *, T=None, P=None, liquid_conversion=None, lle=False):
242277 z = np .asarray (z , float )
243278 if T :
244279 if P : raise ValueError ("may specify either T or P, not both" )
245- P , * args = self .solve_Py (z , T , liquid_conversion , lle )
280+ P , * args = self .solve_Py (z , T , liquid_conversion , lle , full = True )
246281 elif P :
247- T , * args = self .solve_Ty (z , P , liquid_conversion , lle )
282+ T , * args = self .solve_Ty (z , P , liquid_conversion , lle , full = True )
248283 else :
249284 raise ValueError ("must specify either T or P" )
250285 if liquid_conversion :
251286 return ReactiveBubblePointValues (T , P , self .IDs , z , * args )
252287 else :
253288 return BubblePointValues (T , P , self .IDs , z , * args )
254289
255- def solve_Ty (self , z , P , liquid_conversion = None , lle = False ):
290+ def solve_Ty (self , z , P , liquid_conversion = None , lle = False , full = False ):
256291 """
257292 Bubble point at given composition and pressure.
258293
@@ -295,10 +330,13 @@ def solve_Ty(self, z, P, liquid_conversion=None, lle=False):
295330 z_over_P = z / P
296331 T_guess , y = self ._Ty_ideal (z_over_P )
297332 if lle :
333+ x = y .copy ()
334+ α = x .copy ()
298335 f = self ._T_error_lle
299- args = (P , z , y , y . copy () )
336+ args = (P , z , y , x , α )
300337 else :
301338 f = self ._T_error
339+ α = None
302340 args = (P , z_over_P , z , y )
303341 try :
304342 T = flx .aitken_secant (f , T_guess , T_guess + 1e-3 ,
@@ -313,7 +351,8 @@ def solve_Ty(self, z, P, liquid_conversion=None, lle=False):
313351 T_guess , self .T_tol , 5e-12 , args ,
314352 checkiter = False , checkbounds = False ,
315353 maxiter = self .maxiter )
316- return T , fn .normalize (y )
354+ y = fn .normalize (y )
355+ return (T , y , α ) if full else (T , y )
317356 else :
318357 f = self ._T_error_reactive
319358 z_norm = z / z .sum ()
@@ -336,7 +375,7 @@ def solve_Ty(self, z, P, liquid_conversion=None, lle=False):
336375 maxiter = self .maxiter )
337376 return T , dz , fn .normalize (y ), x
338377
339- def solve_Py (self , z , T , liquid_conversion = None , lle = False ):
378+ def solve_Py (self , z , T , liquid_conversion = None , lle = False , full = False ):
340379 """
341380 Bubble point at given composition and temperature.
342381
@@ -379,6 +418,7 @@ def solve_Py(self, z, T, liquid_conversion=None, lle=False):
379418 elif T < self .Tmin : T = self .Tmin
380419 Psats = np .array ([i (T ) for i in self .Psats ])
381420 z = z / z .sum ()
421+ α = None
382422 if self .gamma .P_dependent :
383423 f = self ._P_error_dep
384424 z_Psats = z * Psats
@@ -389,7 +429,9 @@ def solve_Py(self, z, T, liquid_conversion=None, lle=False):
389429 z_Psat_gamma = z * Psats * self .gamma (z , T , 101325 )
390430 P_guess , y = self ._Py_ideal (z_Psat_gamma )
391431 f = self ._P_error_lle
392- args = (P , T , z , Psats , y , y .copy ())
432+ x = y .copy ()
433+ α = x .copy ()
434+ args = (P , T , z , Psats , y , x , α )
393435 else :
394436 z_Psat_gamma = z * Psats * self .gamma (z , T , 101325 )
395437 P_guess , y = self ._Py_ideal (z_Psat_gamma )
@@ -406,7 +448,8 @@ def solve_Py(self, z, T, liquid_conversion=None, lle=False):
406448 P_guess , self .P_tol , 5e-12 , args ,
407449 checkiter = False , checkbounds = False ,
408450 maxiter = self .maxiter )
409- return P , fn .normalize (y )
451+ y = fn .normalize (y )
452+ return (P , y , α ) if full else P , y
410453 else :
411454 f = self ._P_error_reactive
412455 z_norm = z / z .sum ()
0 commit comments