Equilibrium data

Phasepy includes function to fit models for phase equilibria of binary mixtures, the fitted parameters by pairs can be used then with mixtures containing more components. Depending and model, there might be more of one type of phase equilibria. Suppose that the parameters model are represented by \(\underline{\xi}\), the phasepy functions will fit the given experimental data with the followings objectives functions:

If there is Vapor-Liquid Equilibria (VLE):

\[FO_{VLE}(\underline{\xi}) = \sum_{j=1}^{Np} \left[ \sum_{i=1}^c (y_{i,j}^{cal} - y_{i,j}^{exp})^2 + \left( \frac{P_{j}^{cal}}{P_{j}^{exp}} - 1\right)^2 \right]\]

If there is Liquid-Liquid Equilibria (LLE):

\[FO_{LLE}(\underline{\xi}) = \sum_{j=1}^{Np} \sum_{i=1}^c \left[(x_{i,j} - x_{i,j}^{exp})^2 + (w_{i,j} - w_{i,j}^{exp})^2 \right]\]

If there is Vapor-Liquid-Liquid Equilibria (VLLE):

\[FO_{VLLE}(\underline{\xi}) = \sum_{j=1}^{Np} \left[ \sum_{i=1}^c \left[ (x_{i,j}^{cal} - x_{i,j}^{exp})^2 + (w_{i,j}^{cal} - w_{i,j}^{exp})^2 + (y_{i,j}^{cal} - y_{i,j}^{exp})^2 \right] + \left( \frac{P_{j}^{cal}}{P_{j}^{exp}} - 1\right)^2 \right]\]

If there is more than one type of phase equilibria, Phasepy will sum the errors of each one. As an example the parameters for the system of ethanol and water will be fitted, first the experimental data has to be loaded and then set up as a tuple as if shown in the following code block.

>>> #Vapor Liquid equilibria data obtanied from Rieder, Robert M. y A. Ralph Thompson (1949).
>>> # Vapor-Liquid Equilibria Measured by a GillespieStill - Ethyl Alcohol - Water System.
>>> #Ind. Eng. Chem. 41.12, 2905-2908.
>>> datavle = (Xexp, Yexp, Texp, Pexp)

If the system exhibits any other type phase equilibria the necessary tuples would have the following form: >>> datalle = (Xexp, Wexp, Texp, Pexp) >>> datavlle = (Xexp, Wexp, Yexp, Texp, Pexp)

Here, Xexp, Wexp and Yexp are experimental mole fraction for liquid, liquid and vapor phase, respectively. Texp and Pexp are experimental temperature and pressure, respectively.

After the experimental data is available, the mixture with the components is created.

>>> water = component(name = 'Water', Tc = 647.13, Pc = 220.55, Zc = 0.229,
... Vc = 55.948, w = 0.344861, ksv = [ 0.87292043, -0.06844994],
... Ant =  [  11.72091059, 3852.20302815,  -44.10441047])
>>> ethanol = component(name = 'Ethanol', Tc = 514.0, Pc = 61.37, Zc = 0.241,
... Vc = 168.0, w = 0.643558, ksv = [1.27092923, 0.0440421 ],
... Ant = [  12.26474221, 3851.89284329,  -36.99114863])
>>> mix = mixture(ethanol, water)

Fitting QMR mixing rule

As an scalar is been fitted, SciPy recommends to give a certain interval where the minimum could be found, the function fit_kij handles this optimization as follows:

>>> from phasepy.fit import fit_kij
>>> mixkij = mix.copy()
>>> fit_kij((-0.15, -0.05), prsveos, mixkij, datavle)
>>> #optimized kij value
>>> -0.10726854855665718
fit_kij(kij_bounds, eos, mix, datavle=None, datalle=None, datavlle=None, weights_vle=[1.0, 1.0], weights_lle=[1.0, 1.0], weights_vlle=[1.0, 1.0, 1.0, 1.0], minimize_options={})[source]

fit_kij: attemps to fit kij to VLE, LLE, VLLE

Parameters:
  • kij_bounds (tuple) – bounds for kij correction
  • eos (function) – cubic eos to fit kij for qmr mixrule
  • mix (object) – binary mixture
  • datavle (tuple, optional) – (Xexp, Yexp, Texp, Pexp)
  • datalle (tuple, optional) – (Xexp, Wexp, Texp, Pexp)
  • datavlle (tuple, optional) – (Xexp, Wexp, Yexp, Texp, Pexp)
  • weights_vle (list or array_like, optional) – weights_vle[0] = weight for Y composition error, default to 1. weights_vle[1] = weight for bubble pressure error, default to 1.
  • weights_lle (list or array_like, optional) – weights_lle[0] = weight for X (liquid 1) composition error, default to 1. weights_lle[1] = weight for W (liquid 2) composition error, default to 1.
  • weights_vlle (list or array_like, optional) – weights_vlle[0] = weight for X (liquid 1) composition error, default to 1. weights_vlle[1] = weight for W (liquid 2) composition error, default to 1. weights_vlle[2] = weight for Y (vapor) composition error, default to 1. weights_vlle[3] = weight for equilibrium pressure error, default to 1.
  • minimize_options (dict) – Dictionary of any additional spefication for scipy minimize_scalar
Returns:

fit – Result of SciPy minimize

Return type:

OptimizeResult

Fitting NRTL parameters

As an array is been fitted, multidimentional optimization alogirthms are used, the function fit_nrtl handles this optimization with several options available. If a fixed value of the aleatory factor is used the initial guess has the following form:

>>> nrtl0 = np.array([A12, A21])
>>> from phasepy.fit import fit_nrtl
>>> mixnrtl = mix.copy()
>>> #Initial guess of A12, A21
>>> nrtl0 = np.array([-80.,  650.])
>>> fit_nrtl(nrtl0, mixnrtl, datavle, alpha_fixed = True)
>>> #optimized values
>>> [-84.77530335, 648.78439102]

By default bubble points using activity coefficient models use Tsonopoulos virial correlation, if desired ideal gas or Abbott correlation can be used.

>>> from phasepy import ideal_gas, Abbott
>>> #Initial guess of A12, A21
>>> nrtl0 = np.array([-80.,  650.])
>>> fit_nrtl(nrtl0, mixnrtl, datavle, alpha_fixed = True, virialmodel = 'ideal_gas')
>>> #optimized values
>>> [-86.22483806, 647.6320968 ]
>>> fit_nrtl(nrtl0, mixnrtl, datavle, alpha_fixed = True, virialmodel = 'Abbott')
>>> #optimized values
>>> [-84.81672981, 648.75311712]

By default the aleatory factor is set to 0.2, this value ca be changed by passing another value to alpha0 to the fitting function.

>>> fit_nrtl(nrtl0, mixnrtl, datavle, alpha_fixed = True, alpha0 = 0.3)
>>> #optimized values
>>> [-57.38407954, 664.29319445]

If the aleatory factor needs to be optimized it can be included setting alpha_fixed to False, in this case the initial guess has the following form:

>>> nrtl0 = np.array([A12, A21, alpha])
>>> #Initial guess of A12, A21
>>> nrtl0 = np.array([-80.,  650.,  0.2])
>>> fit_nrtl(nrtl0, mixnrtl, datavle, alpha_fixed = False)
>>> #optimized values for A12, A21, alpha
>>> [-5.53112687e+01,  6.72701992e+02,  3.19740734e-01]

Temperature dependent parameters can be fitted setting the option Tdep = True in fit_nrtl, when this option is used the parameters are computed as:

\[\begin{split}A12 = A12_0 + A12_1 T \\ A21 = A21_0 + A21_1 T\end{split}\]

The initial guess passed to the fit function has the following form:

>>> nrtl0 = np.array([A12_0, A21_0, A12_1, A21_1, alpha])

or, if alpha fixed is used.

>>> nrtl0 = np.array([A12_0, A21_0, A12_1, A21_1])
fit_nrtl(x0, mix, datavle=None, datalle=None, datavlle=None, alpha_fixed=False, alpha0=0.2, Tdep=False, virialmodel='Tsonopoulos', weights_vle=[1.0, 1.0], weights_lle=[1.0, 1.0], weights_vlle=[1.0, 1.0, 1.0, 1.0], minimize_options={})[source]

fit_nrtl: attemps to fit nrtl parameters to VLE, LLE, VLLE

Parameters:
  • x0 (array_like) – initial values interaction parameters (and aleatory factor)
  • mix (object) – binary mixture
  • datavle (tuple, optional) – (Xexp, Yexp, Texp, Pexp)
  • datalle (tuple, optional) – (Xexp, Wexp, Texp, Pexp)
  • datavlle (tuple, optional) – (Xexp, Wexp, Yexp, Texp, Pexp)
  • alpha_fit (bool, optional) – if True fix aleatory factor to the value of alpha0
  • alpha0 (float) – value of aleatory factor if fixed
  • Tdep (bool, optional) – Wheter the energy parameters have a temperature dependence
  • virialmodel (function) – function to compute virial coefficients, available options are ‘Tsonopoulos’, ‘Abbott’ or ‘ideal_gas’
  • weights_vle (list or array_like, optional) – weights_vle[0] = weight for Y composition error, default to 1. weights_vle[1] = weight for bubble pressure error, default to 1.
  • weights_lle (list or array_like, optional) – weights_lle[0] = weight for X (liquid 1) composition error, default to 1. weights_lle[1] = weight for W (liquid 2) composition error, default to 1.
  • weights_vlle (list or array_like, optional) – weights_vlle[0] = weight for X (liquid 1) composition error, default to 1. weights_vlle[1] = weight for W (liquid 2) composition error, default to 1. weights_vlle[2] = weight for Y (vapor) composition error, default to 1. weights_vlle[3] = weight for equilibrium pressure error, default to 1.
  • minimize_options (dict) – Dictionary of any additional spefication for scipy minimize

Notes

if Tdep True parameters are treated as:
a12 = a12_1 + a12T * T a21 = a21_1 + a21T * T
if alpha_fixed False and Tdep True:
x0 = [a12, a21, a12T, a21T, alpha]
if alpha_fixed False and Tdep False:
x0 = [a12, a21, alpha]
if alpha_fixed True and Tdep False:
x0 = [a12, a21]
Returns:fit – Result of SciPy minimize
Return type:OptimizeResult

Fitting Wilson’s model parameters

As an array is been fitted, multidimentional optimization alogirthms are used, the function fit_wilson handles this optimization.

>>> from phasepy.fit import fit_wilson
>>> mixwilson = mix.copy()
>>> #Initial guess of A12, A21
>>> wilson0 = np.array([-80.,  650.])
>>> fit_wilson(wilson0, mixwilson, datavle)
>>> #optimized values
>>> [163.79243953, 497.05518499]

Tsonopoulos virial correlation is used by default, if desired ideal gas or Abbott correlation can be used.

>>> fit_wilson(wilson0, mixwilson, datavle, virialmodel = 'ideal_gas')
>>> #optimized value
>>> [105.42279401, 517.2221969 ]
fit_wilson(x0, mix, datavle, virialmodel='Tsonopoulos', weights_vle=[1.0, 1.0], minimize_options={})[source]

fit_wilson: attemps to fit wilson parameters to VLE

Parameters:
  • x0 (array_like) – initial values a12, a21 in K
  • mix (object) – binary mixture
  • datavle (tuple) – (Xexp, Yelv, Texp, Pexp)
  • virialmodel (function) – function to compute virial coefficients, available options are ‘Tsonopoulos’, ‘Abbott’ or ‘ideal_gas’
  • weights_vle (list or array_like, optional) – weights_vle[0] = weight for vapor composition error, default to 1. weights_vle[1] = weight for bubble pressure error, default to 1.
  • minimize_options (dict) – Dictionary of any additional spefication for scipy minimize
Returns:

fit – Result of SciPy minimize

Return type:

OptimizeResult

Fitting Redlich-Kister interaction parameters

As an array is been fitted, multidimentional optimization alogirthms are used, the function fit_rk handles this optimization. Redlich-Kister expansion is programmed for n terms of the expansion, this fitting function will optimize considering the lenght of the array passed as an initial guess.

If rk0 is an scalar it reduced to Porter model, if it is array of size 2 it reduces to Margules Model.

>>> from phasepy.fit import fit_rk
>>> mixrk = mix.copy()
>>> rk0 = np.array([0, 0])
>>> fit_rk(rk0, mixrk, datavle, Tdep =  False)
>>> #optimized values
>>> [ 1.1759649 , -0.44487888]

Temperature dependent parameters can be fitted in which case the initial guess will be splitted into two arrays.

>>> c, c1 = np.split(rk0, 2)

Finally the parameters are computed as \(G = c + c1/T\).

Similarly as NRTl and Wilson’s model, virial correlation can be changed by passing the desired function to the virialmodel argument.

>>> fit_rk(rk0, mixrk, datavle, Tdep =  False, virialmodel = 'ideal_gas')
>>> [ 1.16854714, -0.43874371]
fit_rk(inc0, mix, datavle=None, datalle=None, datavlle=None, Tdep=False, virialmodel='Tsonopoulos', weights_vle=[1.0, 1.0], weights_lle=[1.0, 1.0], weights_vlle=[1.0, 1.0, 1.0, 1.0], minimize_options={})[source]

fit_rk: attemps to fit RK parameters to VLE, LLE, VLLE

Parameters:
  • inc0 (array_like) – initial values to RK parameters
  • mix (object) – binary mixture
  • datavle (tuple, optional) – (Xexp, Yexp, Texp, Pexp)
  • datalle (tuple, optional) – (Xexp, Wexp, Texp, Pexp)
  • datavlle (tuple, optional) – (Xexp, Wexp, Yexp, Texp, Pexp)
  • Tdep (bool,) – wheter the parameter will have a temperature dependence
  • virialmodel (function) – function to compute virial coefficients, available options are ‘Tsonopoulos’, ‘Abbott’ or ‘ideal_gas’
  • weights_vle (list or array_like, optional) – weights_vle[0] = weight for Y composition error, default to 1. weights_vle[1] = weight for bubble pressure error, default to 1.
  • weights_lle (list or array_like, optional) – weights_lle[0] = weight for X (liquid 1) composition error, default to 1. weights_lle[1] = weight for W (liquid 2) composition error, default to 1.
  • weights_vlle (list or array_like, optional) – weights_vlle[0] = weight for X (liquid 1) composition error, default to 1. weights_vlle[1] = weight for W (liquid 2) composition error, default to 1. weights_vlle[2] = weight for Y (vapor) composition error, default to 1. weights_vlle[3] = weight for equilibrium pressure error, default to 1.
  • minimize_options (dict) – Dictionary of any additional spefication for scipy minimize

Notes

if Tdep true:
C = C’ + C’T
if Tdep true:
inc0 = [C’0, C’1, C’2, …, C’0T, C’1T, C’2T… ]
if Tdep false:
inc0 = [C0, C1, C2…]
Returns:fit – Result of SciPy minimize
Return type:OptimizeResult

Multidimentional minimization in SciPy are perfomed with minimize function, aditional command can be passed to this function in order to change tolerance, number of function evaluations or mimization method. This is done by passing a dictionary with the settings to minimize_options in fit_nrtl, fit_wilson or fit_rk. For example:

>>> #changing the minimization method
>>> minimize_options = {'method' : 'Powell'}
>>> fit_rk(rk0, mixrk, datavle, Tdep =  False, minimize_options = minimize_options )

The fitted parameters can be compared against the equilibrium data for each model. The following figure shows the perfomance of QMR, NRTL model, Wilson model and Redlich Kister expansion.

../_images/binaryfit.jpg