{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "*This notebook contains course material from [CBE20255](https://jckantor.github.io/CBE20255)\n", "by Jeffrey Kantor (jeff at nd.edu); the content is available [on Github](https://github.com/jckantor/CBE20255.git).\n", "The text is released under the [CC-BY-NC-ND-4.0 license](https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode),\n", "and code is released under the [MIT license](https://opensource.org/licenses/MIT).*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "< [Bubble and Dew Points for Binary Mixtures](http://nbviewer.jupyter.org/github/jckantor/CBE20255/blob/master/notebooks/07.07-Bubble-and-Dew-Points-for-Binary-Mixtures.ipynb) | [Contents](toc.ipynb) | [Isothermal Flash and the Rachford-Rice Equation](http://nbviewer.jupyter.org/github/jckantor/CBE20255/blob/master/notebooks/07.09-Isothermal-Flash-and-the-Rachford-Rice-Equation.ipynb) >

\"Open" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "NSk3_BVfzhGs" }, "source": [ "# Bubble and Dew Points for Multicomponent Mixtures" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "NSk3_BVfzhGs" }, "source": [ "## Summary\n", "\n", "This notebook illustrates the use of Raoult's Law and Antoine's equation to compute the bubble and dew points for an ideal solution. The video is used with permission from [LearnChemE](http://learncheme.ning.com/), a project at the University of Colorado funded by the National Science Foundation and the Shell Corporation." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "ZWd3C8qizhGu" }, "source": [ "## Bubble and Dew Point Equations for Ideal Mixtures" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "zqQDD6gfzhGu" }, "source": [ "Initialize the IPython workspace with with default settings for plots." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": {}, "colab_type": "code", "id": "AH6UXaCFzhGw" }, "outputs": [], "source": [ "import numpy as np\n", "import matplotlib.pyplot as plt\n", "%matplotlib inline" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": {}, "colab_type": "code", "id": "NEjhIwhozhG0" }, "outputs": [], "source": [ "from IPython.display import YouTubeVideo\n", "YouTubeVideo('theq1Go858E') " ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "JKZe0OJ6zhG5" }, "source": [ "Bubble and dew point calculations for ideal mixtures are all about solving a fixed set of equations. If we have $N$ chemical species, and refer to the liquid phase mole fractions as $x_1, \\ldots, x_N$ and the vapor phase mole fractions as $y_1, \\ldots, y_N$, then two of these equations are\n", "\n", "$$x_1 + x_2 + \\cdots + x_N = 1$$\n", "\n", "and\n", "\n", "$$y_1 + y_2 + \\cdots + y_N = 1$$\n", "\n", "The remaining equations come from Raoult's law. For each of the $n = 1, 2, \\ldots, N$ species we have an equation\n", "\n", "$$ y_n P = x_n P_n^{sat}(T)$$\n", "\n", "where $P_n^{sat}(T)$ is determined from experimental data or from a correlation such as Antoine's equation. This gives us a total $N+2$ equations. \n", "\n", "The unknown variables are the $N$ values of $x_n$, the $N$ values of $y_n$, plus temperature $T$ and pressure $P$ -- a total $2N + 2$ variables. With this as context, we can identify two types of problems." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "JKZe0OJ6zhG5" }, "source": [ "#### Bubble Point Equations\n", "\n", "If the composition of the liquid phase is known, then the equilibrium equations can be solved for the unknown vapor phase composition\n", "\n", "$$y_n = x_n \\frac{P_n^{sat}(T)}{P}$$\n", "\n", "Substituting these values into the equation $y_1 + y_2 + \\cdots + y_N = 1$ gives an equation.\n", "\n", "$$ x_1\\frac{P_1^{sat}(T)}{P} + \\cdots + x_N \\frac{P_N^{sat}(T)}{P} - 1 = 0$$\n", "\n", "If $P$ is known, then the equilibrium value of $T$ is a root to this equation that can be found using standard root-finding functions in the Python or Matlab libraries.\n", "\n", "If $T$ is known, the solution for $P$ is simply\n", "\n", "$$ P = x_1 P_1^{sat}(T) + x_2 P_2^{sat}(T) + \\cdots + x_N P_N^{sat}(T)$$\n", "\n", "Once both $T$ and $P$ are known, the vapor phase composition can be computed by substituting those values back into the first equation." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "JKZe0OJ6zhG5" }, "source": [ "#### Dew Point Equations\n", "\n", "If the composition of the vapor phase is known, then the equilibrium equations can be solved for the unknown vapor liquid phase composition\n", "\n", "$$x_n = y_n \\frac{P}{P_n^{sat}(T)}$$\n", "\n", "Substituting these values into the equation $x_1 + x_2 + \\cdots + x_N = 1$ gives an equation\n", "\n", "$$ y_1\\frac{P}{P_1^{sat}(T)} + \\cdots + y_N \\frac{P}{P_N^{sat}(T)} - 1 = 0$$\n", "\n", "If $P$ is known, then the equilibrium value of $T$ is a root to this equation that can be found using standard root-finding functions in the Python or Matlab libraries.\n", "\n", "If $T$ is known, the solution for $P$ is \n", "\n", "$$\\frac{1}{P} = \\frac{y_1}{P_1^{sat}(T)} + \\frac{y_2}{P_2^{sat}(T)} + \\cdots + \\frac{y_N}{P_N^{sat}(T)}$$\n", "\n", "Once both $T$ and $P$ are known, the liquid phase composition can be computed by substituting those values back into the first equation." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "QJMJmF3NzhG7" }, "source": [ "## Multicomponent Mixtures" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": {}, "colab_type": "code", "id": "yKu1fdfNzhG7" }, "outputs": [], "source": [ "Psat = dict()\n", "Psat['acetone'] = lambda T: 10**(7.02447 - 1161.0/(224 + T))\n", "Psat['benzene'] = lambda T: 10**(6.89272 - 1203.531/(219.888 + T))\n", "Psat['ethanol'] = lambda T: 10**(8.04494 - 1554.3/(222.65 + T))\n", "Psat['toluene'] = lambda T: 10**(6.95805 - 1346.773/(219.693 + T))" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "BNCZ97A5zhG-" }, "source": [ "For the multicomponent case we will use Python dictionaries to store compositions of the liquid phases. Bubble point functions.\n", "\n", "Here we use the `fsolve` function from the scipy.optimize library to return the root of this equation. Note that `fsolve` returns a list of roots, so the terminal `[0]` on the expression selects the first root (and presumably only) of the bubble point equation." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": {}, "colab_type": "code", "id": "ygWSHbGMzhG-" }, "outputs": [], "source": [ "from scipy.optimize import fsolve\n", "def Tbub(species,x):\n", " return fsolve(lambda T : sum([x[s]*Psat[s](T)/P for s in species]) - 1.0,60)[0]\n", "\n", "def ybub(species,x):\n", " return {s: x[s]*Psat[s](Tbub(species,x))/P for s in species}" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "XccSYIR6zhHB" }, "source": [ "Dew point functions" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": {}, "colab_type": "code", "id": "eWyrZvQjzhHC" }, "outputs": [], "source": [ "def Tdew(species,y):\n", " return fsolve(lambda T : sum([y[s]*P/Psat[s](T) for s in species]) - 1.0,60)[0]\n", "\n", "def xdew(species,y):\n", " return {s: y[s]*P/Psat[s](Tdew(species,y)) for s in species}" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "DQjQCWy5zhHF" }, "source": [ "Demonstration" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": {}, "colab_type": "code", "id": "Z8EfMViMzhHF" }, "outputs": [], "source": [ "species = ['acetone','benzene','toluene']\n", "z = dict()\n", "\n", "P = 0.8*760\n", "z['acetone'] = 0.1\n", "z['benzene'] = 0.3\n", "z['toluene'] = 0.6\n", "\n", "print(\"\\nBubble Point Calculations\")\n", "\n", "x = z\n", "T = Tbub(species,x)\n", "y = ybub(species,x)\n", "\n", "print(\"Temperature = {:5.2f} [deg C]\".format(T))\n", "print(\"Pressure = {:7.2f} [mmHg]\".format(P))\n", "print(\" Composition x[s] y[s]\")\n", "for s in species:\n", " print(\" {:10s} {:6.3f} {:6.3f}\".format(s,x[s],y[s]))\n", "\n", "print(\"\\nDew Point Calculations\")\n", "\n", "y = z\n", "T = Tdew(species,y)\n", "x = xdew(species,y)\n", "\n", "print(\"Temperature = {:5.2f} [deg C]\".format(T))\n", "print(\"Pressure = {:7.2f} [mmHg]\".format(P))\n", "print(\" Composition x[s] y[s]\")\n", "for s in species:\n", " print(\" {:10s} {:6.3f} {:6.3f}\".format(s,x[s],y[s]))\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": {}, "colab_type": "code", "id": "qnlTtuvwzhHK" }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "< [Bubble and Dew Points for Binary Mixtures](http://nbviewer.jupyter.org/github/jckantor/CBE20255/blob/master/notebooks/07.07-Bubble-and-Dew-Points-for-Binary-Mixtures.ipynb) | [Contents](toc.ipynb) | [Isothermal Flash and the Rachford-Rice Equation](http://nbviewer.jupyter.org/github/jckantor/CBE20255/blob/master/notebooks/07.09-Isothermal-Flash-and-the-Rachford-Rice-Equation.ipynb) >

\"Open" ] } ], "metadata": { "colab": { "collapsed_sections": [], "name": "Bubble_and_Dew_Points_for_Multicomponent_Mixtures.ipynb", "provenance": [], "version": "0.3.2" }, "kernelspec": { "display_name": "Python 3", "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.7.3" } }, "nbformat": 4, "nbformat_minor": 2 }