{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "*This notebook contains course material from [CBE30338](https://jckantor.github.io/CBE30338)\n", "by Jeffrey Kantor (jeff at nd.edu); the content is available [on Github](https://github.com/jckantor/CBE30338.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", "< [Exothermic Continuous Stirred Tank Reactor](http://nbviewer.jupyter.org/github/jckantor/CBE30338/blob/master/notebooks/02.06-Exothermic-CSTR.ipynb) | [Contents](toc.ipynb) | [Model Library](http://nbviewer.jupyter.org/github/jckantor/CBE30338/blob/master/notebooks/02.08-Model-Library.ipynb) >
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Fed-Batch Bioreactor"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Model Development\n",
"\n",
"Mass balances for a fed-batch bioreactor are given by\n",
"\n",
"$$\\begin{align*}\n",
"\\frac{d(XV)}{dt} & = V r_g(X,S) \\\\\n",
"\\frac{d(PV)}{dt} & = V r_P(X,S) \\\\\n",
"\\frac{d(SV)}{dt} & = F S_f - \\frac{1}{Y_{X/S}}V r_g(X,S)\n",
"\\end{align*}$$\n",
"\n",
"where $X$ is cell concentration, $P$ is product concentration, and $S$ is substrate concentration, all given in units of grams/liter. The reactor is fed with fresh substrate at concentration $S_f$ and flowrate $F(t)$ in liters per hour. The volume (in liters) is therefore changing \n",
"\n",
"$$\\frac{dV}{dt} = F(t)$$\n",
"\n",
"Rate $r_g(X,S)$ is the production of fresh cell biomass in units of grams/liter/hr. The cell specific growth is expressed as\n",
"\n",
"$$r_g(X,S) = \\mu(S)X$$\n",
"\n",
"where $\\mu(S)$ is the cell specific growth rate. In the Monod model, the specific growth rate is a function of substrate concentration given by\n",
"\n",
"$$\\mu(S) = \\mu_{max}\\frac{S}{K_S + S}$$\n",
"\n",
"where $\\mu_{max}$ is the maximum specific growth rate, and $K_S$ is the half saturation constant which is the value of $S$ for which $\\mu = \\frac{1}{2}\\mu_{max}$.\n",
"\n",
"For this model, the product is assumed to be a by-product of cell growth\n",
"\n",
"$$r_P(X,S) = Y_{P/X}r_g(X,S)$$\n",
"\n",
"where $Y_{P/X}$ is the product yield coefficient defined as\n",
"\n",
"$$Y_{P/X} = \\frac{\\mbox{mass of product formed}}{\\mbox{mass of new cells formed}}$$\n",
"\n",
"The model further assumes that substrate is consumed is proportion to the mass of new cells formed where $Y_{X/S}$ is the yield coefficient for new cells\n",
"\n",
"$$Y_{P/X} = \\frac{\\mbox{mass of new cells formed}}{\\mbox{mass of substrate consumed}}$$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Dilution Effect\n",
"\n",
"One aspect of the fed-batch model is that volume is not constant, therefore the cell, product, and substrate concentrations are subject to a dilution effect. Mathematically, the chain rule of differential calculus provides a means to recast the state of model in terms of the intensive concentration variables $X$, $P$, and $S$, and extensive volume $V$.\n",
"\n",
"$$\\begin{align*}\n",
"\\frac{d(XV)}{dt} & = V\\frac{dX}{dt} + X\\frac{dV}{dt} = V\\frac{dX}{dt} + F(t)X \\\\\n",
"\\frac{d(PV)}{dt} & = V\\frac{dP}{dt} + P\\frac{dV}{dt} = V\\frac{dP}{dt} + F(t)P \\\\\n",
"\\frac{d(SV)}{dt} & = V\\frac{dS}{dt} + S\\frac{dV}{dt} = V\\frac{dS}{dt} + F(t)S\n",
"\\end{align*}$$\n",
"\n",
"Rearranging and substituting into the mass balances gives\n",
"\n",
"$$\\begin{align*}\n",
"\\frac{dX}{dt} & = - \\frac{F(t)}{V}X + r_g(X,S) \\\\\n",
"\\frac{dP}{dt} & = - \\frac{F(t)}{V}P + r_P(X,S) \\\\\n",
"\\frac{dS}{dt} & = \\frac{F(t)}{V}(S_f - S) - \\frac{1}{Y_{X/S}}r_g(X,S) \\\\\n",
"\\frac{dV}{dt} & = F(t)\n",
"\\end{align*}$$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Python Implementation"
]
},
{
"cell_type": "code",
"execution_count": 83,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib inline\n",
"\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"from scipy.integrate import odeint\n",
"\n",
"# parameter values\n",
"\n",
"mumax = 0.20 # 1/hour\n",
"Ks = 1.00 # g/liter\n",
"Yxs = 0.5 # g/g\n",
"Ypx = 0.2 # g/g\n",
"Sf = 10.0 # g/liter\n",
"\n",
"# inlet flowrate\n",
"\n",
"def F(t):\n",
" return 0.05\n",
"\n",
"# reaction rates\n",
"\n",
"def mu(S):\n",
" return mumax*S/(Ks + S)\n",
"\n",
"def Rg(X,S):\n",
" return mu(S)*X\n",
" \n",
"def Rp(X,S):\n",
" return Ypx*Rg(X,S)\n",
"\n",
"# differential equations\n",
"\n",
"def xdot(x,t):\n",
" X,P,S,V = x\n",
" dX = -F(t)*X/V + Rg(X,S)\n",
" dP = -F(t)*P/V + Rp(X,S)\n",
" dS = F(t)*(Sf-S)/V - Rg(X,S)/Yxs\n",
" dV = F(t)\n",
" return [dX,dP,dS,dV]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Simulation"
]
},
{
"cell_type": "code",
"execution_count": 84,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
" "
]
}
],
"metadata": {
"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.4"
}
},
"nbformat": 4,
"nbformat_minor": 2
}