{ "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) >
"
]
},
{
"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) >
"
]
}
],
"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
}