{ "cells": [ { "cell_type": "markdown", "id": "b5610399", "metadata": {}, "source": [ "# UNIFAC models\n", "\n", "UNIFAC (UNIQUAC Functional-group Activity Coefficients) is an Excess Gibbs\n", "free energy model used to estimate activity coefficients in non-ideal mixtures.\n", "It is particularly useful for predicting the phase behavior of chemical\n", "mixtures, including liquid-liquid equilibrium (LLE) and vapor-liquid\n", "equilibrium (VLE). In this model the Excess Gibbs free energy is calculated\n", "from the contribution of a combinatorial term and a residual term.\n", "\n", "$$ \\frac{G^E}{RT} = \\frac{G^{E,r}}{RT} + \\frac{G^{E,c}}{RT} $$\n", "\n", "Being:\n", "\n", "- Combinatorial: Accounts for the size and shape of the molecules.\n", "\n", "- Residual: Accounts for the energy interactions between different functional groups.\n", "\n", "Each substance of a mixture modeled with UNIFAC must be represented by a\n", "list a functional groups and other list with the ocurrence of each functional\n", "group on the substance.\n", "\n", "## Combinatorial term\n", "Combinatorial term has two parameters \\(z\\) and \\(d\\). The \\(z\\) parameter is\n", "always set to 10, and the \\(d\\) parameter is set to 1 for the Classic\n", "Liquid-Vapor UNIFAC model and the PSRK-UNIFAC model, and 3/4 for the\n", "Dortmund-UNIFAC model.\n", "\n", "### Flory-Huggins\n", "\n", "$$\n", " G^{E,FH} =\n", " RT \\left(\\sum_i^{NC} n_i \\, \\text{ln} \\, r_i^d\n", " - n \\, \\text{ln} \\, \\sum_j^{NC} n_j r_j^d\n", " + n \\, \\text{ln} \\, n \\right)\n", "$$\n", "\n", "### Staverman-Guggenheim\n", "\n", "$$\n", " \\frac{G^{E,SG}}{RT} =\n", " \\frac{z}{2} \\sum_i^{NC} n_i q_i\n", " \\left(\\text{ln} \\frac{q_i}{r_i}\n", " - \\text{ln} \\, \\sum_j^{NC} n_j q_j\n", " + \\text{ln} \\, \\sum_j^{NC} n_j r_j \\right)\n", "$$\n", "\n", "### Fredenslund et al. (UNIFAC)\n", "\n", "The complete combinatorial term is given by the sum of the Flory-Huggins and\n", "Staverman-Guggenheim terms:\n", "\n", "$$\n", " \\frac{G^{E,\\text{UNIFAC}}}{RT} =\n", " \\frac{G^{E,FH}}{RT} + \\frac{G^{E,SG}}{RT}\n", "$$\n", "\n", "## Residual term\n", "Evaluate the UNIFAC residual term. Check the temperature function $E_{jk}$.\n", "This temperature function is different for each UNIFAC model. The residual\n", "Gibbs excess energy and its derivatives are evaluated as:\n", "\n", "$$\n", " \\frac{G^{E,R}}{RT} = - \\sum_i^{NC} n_i \\sum_k^{NG} v_k^i Q_k\n", " (\\Lambda_k - \\Lambda_k^i)\n", "$$\n", "\n", "With:\n", "\n", "$$\n", " \\Lambda_k = \\text{ln} \\, \\sum_{j}^{NG} \\Theta_j E_{jk}\n", "$$\n", "\n", "$$\n", " \\Lambda_k^i = \\text{ln} \\, \\sum_{j}^{NG} \\Theta_j^i E_{jk}\n", "$$\n", "\n", "$$\n", " E_{jk} = \\text{exp} \\left(- \\frac{U_{jk}}{RT} \\right)\n", "$$\n", "\n", "$$\n", " \\Theta_j = \\frac{Q_j \\displaystyle \\sum_{l}^{NC} n_l v_j^l}\n", " {\\displaystyle \\sum_{k}^{NC} n_k \\sum_{m}^{NG} v_m^l Q_m}\n", "$$\n", "\n", "$$\n", " \\Theta_j^i = \\frac{Q_j v_j^i}{\\displaystyle \\sum_k^{NG} v_k^i Q_k}\n", "$$\n", "\n", "\n", "## Using `ugropy` to retrieve UNIFAC functional groups\n", "\n", "Our research group has another Python package called `ugropy`\n", "\n", "https://github.com/ipqa-research/ugropy\n", "\n", "That package can be used to retrieve the functional groups of a molecule by its\n", "SMILES, or name. Here it's a little example of how to use it. Please refer\n", "to the `ugropy` documentation for more information.\n", "\n", "The package can be installed with:\n", "\n", "```bash\n", "pip install ugropy\n", "```\n", "\n", "## Liquid-Vapor UNIFAC\n", "\n", "This is the original and classic Liquid-Vapor UNIFAC model. In this model, the\n", "parameters are defined as:\n", "$$\n", " z = 10\n", "$$\n", "\n", "$$\n", " d = 1\n", "$$\n", "\n", "The temperature function $E_{jk}$ is defined with a single temperature \n", "constant $a_{jk}$ coefficient as follows:\n", "\n", "$$\n", " E_{jk} = \\text{exp} \\left(- \\frac{U_{jk}}{RT} \\right) = \\text{exp} \\left(- \\frac{a_{jk}}{T} \\right)\n", "$$" ] }, { "cell_type": "code", "execution_count": 1, "id": "235a655f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0.17122481, 0.07250592])" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import yaeos\n", "\n", "\n", "# UNIFAC functional groups: n-hexane - toluene\n", "groups = [ # Functional groups of each molecule\n", " {1: 2, 2: 4}, # {\"CH3\": 2, \"CH2\": 4}\n", " {9: 5, 11: 1}, # {\"ACH\": 5, \"ACCH3\": 1}\n", "]\n", "\n", "model = yaeos.UNIFACVLE(groups)\n", "\n", "n = [4.0, 6.0] # number of moles [mol]\n", "T = 303.15 # temperature [K]\n", "\n", "model.ln_gamma(n, T)" ] }, { "cell_type": "markdown", "id": "ae5fe9ad", "metadata": {}, "source": [ "You can retrieve the UNIFACVLE groups with `ugropy` as:" ] }, { "cell_type": "code", "execution_count": 2, "id": "9505e7c9", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[{1: 2, 2: 4}, {9: 5, 11: 1}]\n" ] } ], "source": [ "import ugropy as ug\n", "\n", "\n", "names = [\"hexane\", \"toluene\"]\n", "\n", "ugropy_groups = [ug.unifac.get_groups(n).subgroups_num for n in names]\n", "\n", "print(ugropy_groups)" ] }, { "cell_type": "code", "execution_count": 3, "id": "94a0ca08", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0.17122481, 0.07250592])" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model = yaeos.UNIFACVLE(ugropy_groups)\n", "\n", "model.ln_gamma(n, T)" ] }, { "cell_type": "markdown", "id": "77539e0f", "metadata": {}, "source": [ "## PSRK UNIFAC\n", "\n", "This is the Predictive Soave-Redlich-Kwong (PSRK) UNIFAC model. In this model,\n", "the parameters are defined as:\n", "\n", "$$\n", " z = 10\n", "$$\n", "\n", "$$\n", " d = 1\n", "$$\n", "\n", "The temperature function $E_{jk}$ is defined with a quadratic temperature\n", "function as follows:\n", "\n", "$$\n", " E_{jk} = \\text{exp} \\left(- \\frac{U_{jk}}{RT} \\right) = \n", " \\text{exp} \\left(- \\frac{a_{jk} + b_{jk} T + c_{jk} T^2}{T} \\right)\n", "$$" ] }, { "cell_type": "code", "execution_count": 4, "id": "d83011d4", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0.17122481, 0.07250592])" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import yaeos\n", "\n", "\n", "# PSRK functional groups: n-hexane - toluene\n", "groups = [ # Functional groups of each molecule\n", " {1: 2, 2: 4}, # {\"CH3\": 2, \"CH2\": 4}\n", " {9: 5, 11: 1}, # {\"ACH\": 5, \"ACCH3\": 1}\n", "]\n", "\n", "model = yaeos.UNIFACPSRK(groups)\n", "\n", "n = [4.0, 6.0] # number of moles [mol]\n", "T = 303.15 # temperature [K]\n", "\n", "model.ln_gamma(n, T)" ] }, { "cell_type": "markdown", "id": "736d283b", "metadata": {}, "source": [ "You can retrieve the PSRK groups with `ugropy` as:" ] }, { "cell_type": "code", "execution_count": 5, "id": "c106bd71", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[{1: 2, 2: 4}, {9: 5, 11: 1}]\n" ] } ], "source": [ "import ugropy as ug\n", "\n", "\n", "names = [\"hexane\", \"toluene\"]\n", "\n", "ugropy_groups = [ug.psrk.get_groups(n).subgroups_num for n in names]\n", "\n", "print(ugropy_groups)" ] }, { "cell_type": "code", "execution_count": 6, "id": "75b23bd9", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0.17122481, 0.07250592])" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model = yaeos.UNIFACPSRK(ugropy_groups)\n", "\n", "model.ln_gamma(n, T)" ] }, { "cell_type": "markdown", "id": "93ed802a", "metadata": {}, "source": [ "## Dortmund UNIFAC\n", "\n", "This is the Dortmund modified UNIFAC model. In this model, the parameters are\n", "defined as:\n", "\n", "$$\n", " z = \\frac{3}{4}\n", "$$\n", "\n", "$$\n", " d = 1\n", "$$\n", "\n", "The temperature function $E_{jk}$ is defined with a quadratic temperature\n", "function as follows:\n", "\n", "$$\n", " E_{jk} = \\text{exp} \\left(- \\frac{U_{jk}}{RT} \\right) = \n", " \\text{exp} \\left(- \\frac{a_{jk} + b_{jk} T + c_{jk} T^2}{T} \\right)\n", "$$" ] }, { "cell_type": "code", "execution_count": 7, "id": "18ff1714", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0.19827923, 0.08808743])" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import yaeos\n", "\n", "\n", "# PSRK functional groups: n-hexane - toluene\n", "groups = [ # Functional groups of each molecule\n", " {1: 2, 2: 4}, # {\"CH3\": 2, \"CH2\": 4}\n", " {9: 5, 11: 1}, # {\"ACH\": 5, \"ACCH3\": 1}\n", "]\n", "\n", "model = yaeos.UNIFACDortmund(groups)\n", "\n", "n = [4.0, 6.0] # number of moles [mol]\n", "T = 303.15 # temperature [K]\n", "\n", "model.ln_gamma(n, T)" ] }, { "cell_type": "markdown", "id": "460a9310", "metadata": {}, "source": [ "You can retrieve the Dortmund UNIFAC groups with `ugropy` as:" ] }, { "cell_type": "code", "execution_count": 8, "id": "de59a414", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[{1: 2, 2: 4}, {9: 5, 11: 1}]\n" ] } ], "source": [ "import ugropy as ug\n", "\n", "\n", "names = [\"hexane\", \"toluene\"]\n", "\n", "ugropy_groups = [ug.dortmund.get_groups(n).subgroups_num for n in names]\n", "\n", "print(ugropy_groups)" ] }, { "cell_type": "code", "execution_count": 9, "id": "c83f9ab2", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0.19827923, 0.08808743])" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model = yaeos.UNIFACDortmund(ugropy_groups)\n", "\n", "model.ln_gamma(n, T)" ] } ], "metadata": { "kernelspec": { "display_name": "yaeos", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.12" } }, "nbformat": 4, "nbformat_minor": 5 }