UNIFAC models

UNIFAC (UNIQUAC Functional-group Activity Coefficients) is an Excess Gibbs free energy model used to estimate activity coefficients in non-ideal mixtures. It is particularly useful for predicting the phase behavior of chemical mixtures, including liquid-liquid equilibrium (LLE) and vapor-liquid equilibrium (VLE). In this model the Excess Gibbs free energy is calculated from the contribution of a combinatorial term and a residual term.

\[\frac{G^E}{RT} = \frac{G^{E,r}}{RT} + \frac{G^{E,c}}{RT}\]

Being:

  • Combinatorial: Accounts for the size and shape of the molecules.

  • Residual: Accounts for the energy interactions between different functional groups.

Each substance of a mixture modeled with UNIFAC must be represented by a list a functional groups and other list with the ocurrence of each functional group on the substance.

Combinatorial term

Combinatorial term has two parameters (z) and (d). The (z) parameter is always set to 10, and the (d) parameter is set to 1 for the Classic Liquid-Vapor UNIFAC model and the PSRK-UNIFAC model, and 3/4 for the Dortmund-UNIFAC model.

Flory-Huggins

\[G^{E,FH} = RT \left(\sum_i^{NC} n_i \, \text{ln} \, r_i^d - n \, \text{ln} \, \sum_j^{NC} n_j r_j^d + n \, \text{ln} \, n \right)\]

Staverman-Guggenheim

\[\frac{G^{E,SG}}{RT} = \frac{z}{2} \sum_i^{NC} n_i q_i \left(\text{ln} \frac{q_i}{r_i} - \text{ln} \, \sum_j^{NC} n_j q_j + \text{ln} \, \sum_j^{NC} n_j r_j \right)\]

Fredenslund et al. (UNIFAC)

The complete combinatorial term is given by the sum of the Flory-Huggins and Staverman-Guggenheim terms:

\[\frac{G^{E,\text{UNIFAC}}}{RT} = \frac{G^{E,FH}}{RT} + \frac{G^{E,SG}}{RT}\]

Residual term

Evaluate the UNIFAC residual term. Check the temperature function \(E_{jk}\). This temperature function is different for each UNIFAC model. The residual Gibbs excess energy and its derivatives are evaluated as:

\[\frac{G^{E,R}}{RT} = - \sum_i^{NC} n_i \sum_k^{NG} v_k^i Q_k (\Lambda_k - \Lambda_k^i)\]

With:

\[\Lambda_k = \text{ln} \, \sum_{j}^{NG} \Theta_j E_{jk}\]
\[\Lambda_k^i = \text{ln} \, \sum_{j}^{NG} \Theta_j^i E_{jk}\]
\[E_{jk} = \text{exp} \left(- \frac{U_{jk}}{RT} \right)\]
\[\Theta_j = \frac{Q_j \displaystyle \sum_{l}^{NC} n_l v_j^l} {\displaystyle \sum_{k}^{NC} n_k \sum_{m}^{NG} v_m^l Q_m}\]
\[\Theta_j^i = \frac{Q_j v_j^i}{\displaystyle \sum_k^{NG} v_k^i Q_k}\]

Using ugropy to retrieve UNIFAC functional groups

Our research group has another Python package called ugropy

https://github.com/ipqa-research/ugropy

That package can be used to retrieve the functional groups of a molecule by its SMILES, or name. Here it’s a little example of how to use it. Please refer to the ugropy documentation for more information.

The package can be installed with:

pip install ugropy

Liquid-Vapor UNIFAC

This is the original and classic Liquid-Vapor UNIFAC model. In this model, the parameters are defined as:

\[z = 10\]
\[d = 1\]

The temperature function \(E_{jk}\) is defined with a single temperature constant \(a_{jk}\) coefficient as follows:

\[E_{jk} = \text{exp} \left(- \frac{U_{jk}}{RT} \right) = \text{exp} \left(- \frac{a_{jk}}{T} \right)\]
[1]:
import yaeos


# UNIFAC functional groups: n-hexane - toluene
groups = [              # Functional groups of each molecule
    {1: 2, 2: 4},       # {"CH3": 2, "CH2": 4}
    {9: 5, 11: 1},      # {"ACH": 5, "ACCH3": 1}
]

model = yaeos.UNIFACVLE(groups)

n = [4.0, 6.0]  # number of moles [mol]
T = 303.15      # temperature [K]

model.ln_gamma(n, T)
[1]:
array([0.17122481, 0.07250592])

You can retrieve the UNIFACVLE groups with ugropy as:

[2]:
import ugropy as ug


names = ["hexane", "toluene"]

ugropy_groups = [ug.unifac.get_groups(n).subgroups_num for n in names]

print(ugropy_groups)
/home/runner/.local/lib/python3.12/site-packages/ugropy/core/get_rdkit_object.py:78: PubChemPyDeprecationWarning: canonical_smiles is deprecated: Use connectivity_smiles instead
  if pcp_object.canonical_smiles:
/home/runner/.local/lib/python3.12/site-packages/ugropy/core/get_rdkit_object.py:79: PubChemPyDeprecationWarning: canonical_smiles is deprecated: Use connectivity_smiles instead
  chem_object = Chem.MolFromSmiles(pcp_object.canonical_smiles)
[{1: 2, 2: 4}, {9: 5, 11: 1}]
[3]:
model = yaeos.UNIFACVLE(ugropy_groups)

model.ln_gamma(n, T)
[3]:
array([0.17122481, 0.07250592])

PSRK UNIFAC

This is the Predictive Soave-Redlich-Kwong (PSRK) UNIFAC model. In this model, the parameters are defined as:

\[z = 10\]
\[d = 1\]

The temperature function \(E_{jk}\) is defined with a quadratic temperature function as follows:

\[E_{jk} = \text{exp} \left(- \frac{U_{jk}}{RT} \right) = \text{exp} \left(- \frac{a_{jk} + b_{jk} T + c_{jk} T^2}{T} \right)\]
[4]:
import yaeos


# PSRK functional groups: n-hexane - toluene
groups = [              # Functional groups of each molecule
    {1: 2, 2: 4},       # {"CH3": 2, "CH2": 4}
    {9: 5, 11: 1},      # {"ACH": 5, "ACCH3": 1}
]

model = yaeos.UNIFACPSRK(groups)

n = [4.0, 6.0]  # number of moles [mol]
T = 303.15      # temperature [K]

model.ln_gamma(n, T)
[4]:
array([0.17122481, 0.07250592])

You can retrieve the PSRK groups with ugropy as:

[5]:
import ugropy as ug


names = ["hexane", "toluene"]

ugropy_groups = [ug.psrk.get_groups(n).subgroups_num for n in names]

print(ugropy_groups)
[{1: 2, 2: 4}, {9: 5, 11: 1}]
[6]:
model = yaeos.UNIFACPSRK(ugropy_groups)

model.ln_gamma(n, T)
[6]:
array([0.17122481, 0.07250592])

Dortmund UNIFAC

This is the Dortmund modified UNIFAC model. In this model, the parameters are defined as:

\[z = \frac{3}{4}\]
\[d = 1\]

The temperature function \(E_{jk}\) is defined with a quadratic temperature function as follows:

\[E_{jk} = \text{exp} \left(- \frac{U_{jk}}{RT} \right) = \text{exp} \left(- \frac{a_{jk} + b_{jk} T + c_{jk} T^2}{T} \right)\]
[7]:
import yaeos


# PSRK functional groups: n-hexane - toluene
groups = [              # Functional groups of each molecule
    {1: 2, 2: 4},       # {"CH3": 2, "CH2": 4}
    {9: 5, 11: 1},      # {"ACH": 5, "ACCH3": 1}
]

model = yaeos.UNIFACDortmund(groups)

n = [4.0, 6.0]  # number of moles [mol]
T = 303.15      # temperature [K]

model.ln_gamma(n, T)
[7]:
array([0.19827923, 0.08808743])

You can retrieve the Dortmund UNIFAC groups with ugropy as:

[8]:
import ugropy as ug


names = ["hexane", "toluene"]

ugropy_groups = [ug.dortmund.get_groups(n).subgroups_num for n in names]

print(ugropy_groups)
[{1: 2, 2: 4}, {9: 5, 11: 1}]
[9]:
model = yaeos.UNIFACDortmund(ugropy_groups)

model.ln_gamma(n, T)
[9]:
array([0.19827923, 0.08808743])