{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# A Simple Staggered FV Code for the Navier-Stokes Equations\n",
"### Tony Saad
Assistant Professor of Chemical Engineering
University of Utah"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"%matplotlib inline\n",
"%config InlineBackend.figure_format = 'svg'\n",
"import matplotlib.pyplot as plt\n",
"import matplotlib.animation as animation\n",
"from matplotlib import cm\n",
"plt.rcParams['animation.html'] = 'html5'\n",
"import time"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Reynolds Number: 1000.0\n",
"dt= 0.0004\n"
]
}
],
"source": [
"# define some boiler plate\n",
"nx = 16\n",
"ny = 16\n",
"# dt = 1.0e-3 # timestep size\n",
"ν = 0.01 # dynamic viscosity\n",
"lx = 1.0\n",
"ly = 1.0\n",
"dx = lx/nx\n",
"dy = ly/ny\n",
"t = 0.0\n",
"\n",
"# cell centered coordinates\n",
"xx = np.linspace(dx/2.0,lx - dx/2.0,nx, endpoint=True)\n",
"yy = np.linspace(dy/2.0,ly - dy/2.0,ny, endpoint=True)\n",
"xcc, ycc = np.meshgrid(xx,yy)\n",
"\n",
"# x-staggered coordinates\n",
"xxs = np.linspace(0,lx,nx+1, endpoint=True)\n",
"xu,yu = np.meshgrid(xxs, yy)\n",
"\n",
"# y-staggered coordinates\n",
"yys = np.linspace(0,ly,ny+1, endpoint=True)\n",
"xv,yv = np.meshgrid(xx, yys)\n",
"\n",
"Ut = 10.0\n",
"Ub = 0.0\n",
"Vl = 0.0\n",
"Vr = 0.0\n",
"print('Reynolds Number:', Ut*lx/ν)\n",
"dt = min(0.25*dx*dx/ν, 4.0*ν/Ut/Ut)\n",
"print('dt=', dt)\n",
"\n",
"# initialize velocities - we stagger everything in the negative direction. A scalar cell owns its minus face, only.\n",
"# Then, for example, the u velocity field has a ghost cell at x0 - dx and the plus ghost cell at lx\n",
"u = np.zeros([ny+2, nx+2]) # include ghost cells\n",
"\n",
"# # same thing for the y-velocity component\n",
"v = np.zeros([ny +2, nx+2]) # include ghost cells\n",
"\n",
"ut = np.zeros_like(u)\n",
"vt = np.zeros_like(u) \n",
"\n",
"# initialize the pressure\n",
"p = np.zeros([nx+2,ny+2]); # include ghost cells\n",
"\n",
"# a bunch of lists for animation purposes\n",
"usol=[]\n",
"usol.append(u)\n",
"\n",
"vsol=[]\n",
"vsol.append(v)\n",
"\n",
"psol = []\n",
"psol.append(p)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"# build pressure coefficient matrix\n",
"Ap = np.zeros([ny+2,nx+2])\n",
"Ae = 1.0/dx/dx*np.ones([ny+2,nx+2])\n",
"As = 1.0/dy/dy*np.ones([ny+2,nx+2])\n",
"An = 1.0/dy/dy*np.ones([ny+2,nx+2])\n",
"Aw = 1.0/dx/dx*np.ones([ny+2,nx+2])\n",
"# set left wall coefs\n",
"Aw[1:-1,1] = 0.0\n",
"# set right wall coefs\n",
"Ae[1:-1,-2] = 0.0\n",
"# set top wall coefs\n",
"An[-2,1:-1] = 0.0\n",
"# set bottom wall coefs\n",
"As[1,1:-1] = 0.0\n",
"Ap = -(Aw + Ae + An + As)\n",
"\n",
"def pressure_poisson2(p, b, dx, dy):\n",
" pn = np.empty_like(p)\n",
" it = 0\n",
" err = 1e5\n",
" tol = 1e-8\n",
" maxit = 100\n",
" β = 1.1\n",
" while err > tol and it < maxit:\n",
" pn = p.copy() \n",
" for i in range(1,nx+1):\n",
" for j in range(1,ny+1):\n",
" ap = Ap[j,i]\n",
" an = An[j,i]\n",
" aso = As[j,i]\n",
" ae = Ae[j,i]\n",
" aw = Aw[j,i]\n",
" rhs = b[j,i] - 1.0*(ae*p[j,i+1] + aw*p[j,i-1] + an*p[j+1,i] + aso*p[j-1,i])\n",
" p[j,i] = β*rhs/ap + (1-β)*p[j,i]\n",
" err = np.linalg.norm(p - pn)\n",
" it += 1\n",
"# print('Poisson Error:', err) \n",
" return p, err"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
""
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
"