最近感觉CSDN有点大病,用各种浏览器都不显示最上面那一栏(就是点赞、数据、发布啥啥的那一栏),今天用ubuntu偶然发现又显示了, 赶紧把之前写的东西发出来记录一下,不知道问题出在哪:(

CFDpython - 12 steps to N-S equation

后面四步,每一步都是一个不同的方程,分别是:二维拉普拉斯方程、二维泊松方程、二维空腔流动、二维管渠流动

Step 9: 2D Laplace Equation

  1. 方程形式如下:
    python计算光流速度 python计算流体力学_二维
  2. 通过观察这个方程可以发现,两项是关于x和y的扩散项方程,因此可以用二阶中心差分进行离散:
    python计算光流速度 python计算流体力学_python_02
  3. 该方程与时间t无关(也就是常说的稳态),那么可以通过迭代的方法求解python计算光流速度 python计算流体力学_二维_03 ,即将离散方程转化为五点差分形式
    python计算光流速度 python计算流体力学_二维_04
  4. 初始条件:python计算光流速度 python计算流体力学_开发语言_05
  5. 边界条件:
  • python计算光流速度 python计算流体力学_笔记_06 at python计算光流速度 python计算流体力学_二维_07
  • python计算光流速度 python计算流体力学_笔记_08 at python计算光流速度 python计算流体力学_笔记_09
  • python计算光流速度 python计算流体力学_python_10 at python计算光流速度 python计算流体力学_笔记_11
  1. 解析解:
    python计算光流速度 python计算流体力学_笔记_12
  2. 代码如下(自己写的,原文可以看最上方的链接)
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm

def plot2D(x,y,p):
    plt.ion() # 这个东西是方便close,不然close不鸟
    fig=plt.figure(figsize=(11,7),dpi=100) # 在Matplotlib 3.4版本之后,将fig.gca弃用了
    ax = fig.add_subplot(projection='3d')

    X,Y=np.meshgrid(x,y)
    surf=ax.plot_surface(X,Y,p[:],rstride=1,cstride=1,cmap=cm.viridis,
                         linewidth=0,antialiased=False)
    ax.set_xlim(0,2)
    ax.set_ylim(0, 1)
    ax.view_init(30,225)


# create x and y coordinate
nx=100
ny=100
x=np.linspace(0,2,nx)
y=np.linspace(0,1,ny)
dx=2/(nx-1)
dy=1/(ny-1)

# initial p
p=np.zeros((nx,ny))

# boundary p
p[0,:]=0
p[-1,:]=y
p[:,0]=p[:,1] # dp/dy=0 at y=0
p[:,-1]=p[:,-2] # dp/dy=0 at y=1

# start iteration
error=1
pn=np.empty_like(p)
while error>=1e-6:
    pn=p.copy()
    p[1:-1,1:-1]=((dy**2*(p[2:,1:-1]+p[0:-2,1:-1]))+dx**2*(p[1:-1,2:]+p[1:-1,0:-2]))/(2*(dx**2+dy**2))

    # boundary
    p[0, :] = 0
    p[-1, :] = y
    p[:, 0] = p[:, 1]  # dp/dy=0 at y=0
    p[:, -1] = p[:, -2]  # dp/dy=0 at y=1

    # error= norm L2
    error=np.linalg.norm(x=p-pn,ord=2)

    # draw in every iteration
    plt.close()
    plot2D(x,y,p)
    plt.show()
    plt.pause(1)

Step 10: 2D Poisson Equation

  1. 这一步作者在最后提到,其实求解这种方程的代码都很像(事实也确实如此,仅仅是边界条件和初始条件不同,离散方程的方法大差不差),如果想规整这些代码,涉及到python中package的概念。
  2. 二维泊松方程的形式如下:
    python计算光流速度 python计算流体力学_python计算光流速度_13
  3. 离散方式和上文大同小异,就是扩散项和常数源项:
    python计算光流速度 python计算流体力学_二维_14
  4. 代码就不贴了,有需要的话看原文去,这里也让笔者大受启发,在求解CFD问题的时候,不要想着一口气吃成一个大胖子,先从稳态方程写起,弄好之后再加非稳态项,最后加源项。

Step 11: Cavity Flow with Navier–Stokes

  1. 这是N-S方程质量和动量守恒方程组:
    python计算光流速度 python计算流体力学_开发语言_15
    python计算光流速度 python计算流体力学_二维_16
  2. 二维方腔流方程形式如下,其中第三个压力的扩散方程就是上一步推出的2维泊松方程,这里由于要分别求压力和流速,可以尝试采用SIMPLE算法python计算光流速度 python计算流体力学_笔记_17

python计算光流速度 python计算流体力学_二维_18

python计算光流速度 python计算流体力学_开发语言_19

  1. 方程离散,作者建议这里要手写一下,原理不难,就是简单的差分罢了,但是很考验一个人的手感:
    python计算光流速度 python计算流体力学_开发语言_20
    python计算光流速度 python计算流体力学_python计算光流速度_21
    python计算光流速度 python计算流体力学_二维_22
  2. 把上一时刻的压力和速度放一侧:
    python计算光流速度 python计算流体力学_开发语言_23
    python计算光流速度 python计算流体力学_python计算光流速度_24
  3. 边界条件:
  • python计算光流速度 python计算流体力学_开发语言_25 at python计算光流速度 python计算流体力学_笔记_26
  • python计算光流速度 python计算流体力学_python计算光流速度_27
  • python计算光流速度 python计算流体力学_python_28 at python计算光流速度 python计算流体力学_python计算光流速度_29;
  • python计算光流速度 python计算流体力学_python_30 at python计算光流速度 python计算流体力学_笔记_26
  • python计算光流速度 python计算流体力学_python计算光流速度_32 at python计算光流速度 python计算流体力学_笔记_33
  1. 代码如下:
import numpy
from matplotlib import pyplot, cm
from mpl_toolkits.mplot3d import Axes3D
%matplotlib inline

nx = 41
ny = 41
nt = 500
nit = 50
c = 1
dx = 2 / (nx - 1)
dy = 2 / (ny - 1)
x = numpy.linspace(0, 2, nx)
y = numpy.linspace(0, 2, ny)
X, Y = numpy.meshgrid(x, y)

rho = 1
nu = .1
dt = .001

u = numpy.zeros((ny, nx))
v = numpy.zeros((ny, nx))
p = numpy.zeros((ny, nx)) 
b = numpy.zeros((ny, nx))

def build_up_b(b, rho, dt, u, v, dx, dy):
    
    b[1:-1, 1:-1] = (rho * (1 / dt * 
                    ((u[1:-1, 2:] - u[1:-1, 0:-2]) / 
                     (2 * dx) + (v[2:, 1:-1] - v[0:-2, 1:-1]) / (2 * dy)) -
                    ((u[1:-1, 2:] - u[1:-1, 0:-2]) / (2 * dx))**2 -
                      2 * ((u[2:, 1:-1] - u[0:-2, 1:-1]) / (2 * dy) *
                           (v[1:-1, 2:] - v[1:-1, 0:-2]) / (2 * dx))-
                          ((v[2:, 1:-1] - v[0:-2, 1:-1]) / (2 * dy))**2))

    return b

def pressure_poisson(p, dx, dy, b):
    pn = numpy.empty_like(p)
    pn = p.copy()
    
    for q in range(nit):
        pn = p.copy()
        p[1:-1, 1:-1] = (((pn[1:-1, 2:] + pn[1:-1, 0:-2]) * dy**2 + 
                          (pn[2:, 1:-1] + pn[0:-2, 1:-1]) * dx**2) /
                          (2 * (dx**2 + dy**2)) -
                          dx**2 * dy**2 / (2 * (dx**2 + dy**2)) * 
                          b[1:-1,1:-1])

        p[:, -1] = p[:, -2] # dp/dx = 0 at x = 2
        p[0, :] = p[1, :]   # dp/dy = 0 at y = 0
        p[:, 0] = p[:, 1]   # dp/dx = 0 at x = 0
        p[-1, :] = 0        # p = 0 at y = 2
        
    return p


def cavity_flow(nt, u, v, dt, dx, dy, p, rho, nu):
    un = numpy.empty_like(u)
    vn = numpy.empty_like(v)
    b = numpy.zeros((ny, nx))
    
    for n in range(nt):
        un = u.copy()
        vn = v.copy()
        
        b = build_up_b(b, rho, dt, u, v, dx, dy)
        p = pressure_poisson(p, dx, dy, b)
        
        u[1:-1, 1:-1] = (un[1:-1, 1:-1]-
                         un[1:-1, 1:-1] * dt / dx *
                        (un[1:-1, 1:-1] - un[1:-1, 0:-2]) -
                         vn[1:-1, 1:-1] * dt / dy *
                        (un[1:-1, 1:-1] - un[0:-2, 1:-1]) -
                         dt / (2 * rho * dx) * (p[1:-1, 2:] - p[1:-1, 0:-2]) +
                         nu * (dt / dx**2 *
                        (un[1:-1, 2:] - 2 * un[1:-1, 1:-1] + un[1:-1, 0:-2]) +
                         dt / dy**2 *
                        (un[2:, 1:-1] - 2 * un[1:-1, 1:-1] + un[0:-2, 1:-1])))

        v[1:-1,1:-1] = (vn[1:-1, 1:-1] -
                        un[1:-1, 1:-1] * dt / dx *
                       (vn[1:-1, 1:-1] - vn[1:-1, 0:-2]) -
                        vn[1:-1, 1:-1] * dt / dy *
                       (vn[1:-1, 1:-1] - vn[0:-2, 1:-1]) -
                        dt / (2 * rho * dy) * (p[2:, 1:-1] - p[0:-2, 1:-1]) +
                        nu * (dt / dx**2 *
                       (vn[1:-1, 2:] - 2 * vn[1:-1, 1:-1] + vn[1:-1, 0:-2]) +
                        dt / dy**2 *
                       (vn[2:, 1:-1] - 2 * vn[1:-1, 1:-1] + vn[0:-2, 1:-1])))

        u[0, :]  = 0
        u[:, 0]  = 0
        u[:, -1] = 0
        u[-1, :] = 1    # set velocity on cavity lid equal to 1
        v[0, :]  = 0
        v[-1, :] = 0
        v[:, 0]  = 0
        v[:, -1] = 0
        
        
    return u, v, p

u = numpy.zeros((ny, nx))
v = numpy.zeros((ny, nx))
p = numpy.zeros((ny, nx))
b = numpy.zeros((ny, nx))
nt = 100 # change to 700
u, v, p = cavity_flow(nt, u, v, dt, dx, dy, p, rho, nu)

fig = pyplot.figure(figsize=(11,7), dpi=100)
# plotting the pressure field as a contour
pyplot.contourf(X, Y, p, alpha=0.5, cmap=cm.viridis)  
pyplot.colorbar()
# plotting the pressure field outlines
pyplot.contour(X, Y, p, cmap=cm.viridis)  
# plotting velocity field
pyplot.quiver(X[::2, ::2], Y[::2, ::2], u[::2, ::2], v[::2, ::2]) 
pyplot.xlabel('X')
pyplot.ylabel('Y');
  1. 也可以用streamplot画图,这样流线是连续的,用quiver画图流线是间断的。
fig = pyplot.figure(figsize=(11, 7), dpi=100)
pyplot.contourf(X, Y, p, alpha=0.5, cmap=cm.viridis)
pyplot.colorbar()
pyplot.contour(X, Y, p, cmap=cm.viridis)
pyplot.streamplot(X, Y, u, v)
pyplot.xlabel('X')
pyplot.ylabel('Y');

Step 12: Channel Flow with Navier–Stokes

  1. 二维管道流就是在u方向的动量方程加了源项F,原文处是采用迭代收敛的方法计算的
  2. 全篇看完后第一感觉就是太浅显了,全文基本是通过有限差分的方式进行求解,然后对于其物理本质基本没有概括。但总而言之,浅显有浅显的好处,非常利好初学者自学,但笔者后期时间有限,加上作者这最后几个步骤同质化过于严重,导致笔者第三篇笔记写的非常水,所以强烈建议有兴趣的读者去看看github原文