【Python4CFD】笔记step5-8

CFDpython - 12 steps to N-S equation

承接上文,这是step5-8,相当于课程的第二阶段,这一阶段主要是讲2维的,先老实把链接放在这:

  1. 课程链接CFD Python, a.k.a. the 12 steps to Navier-Stokes
  2. 视频链接ME702-Youtube

06 Array Operations with NumPy

  1. 在开始前,作者介绍了numpy的数组操作,举了一个很简单的例子,切片计算:
import numpy

u = numpy.array((0, 1, 2, 3, 4, 5))

# 方法一:一个一个算相邻元素的差值
for i in range(1, len(u)):
    print(u[i] - u[i-1])

# 方法二:利用切片直接计算
u[1:] - u[0:-1]
# (array([1, 2, 3, 4, 5])-array([0, 1, 2, 3, 4]))
  1. 其次,作者还重点强调了,使用numpy内置的数组和函数是可以加速运算的(原因在于numpy的底层是C内核,并且在数据结构和算法上做了优化)
  2. 这里需要介绍一下iPython的一个magic function–>%%timeit
    • 这个函数会返回jupyter一段函数的平均执行时间
    • 注意嗷,这个函数是先运行,再计算,如果在这段section里画图了,会重复画一次图!
  3. 例子的代码如下:
#%% 网格划分:求解的是二维对流方程
nx = 81
ny = 81
nt = 100
c = 1
dx = 2 / (nx - 1)
dy = 2 / (ny - 1)
sigma = .2
dt = sigma * dx

x = numpy.linspace(0, 2, nx)
y = numpy.linspace(0, 2, ny)

u = numpy.ones((ny, nx)) ##create a 1xn vector of 1's
un = numpy.ones((ny, nx)) 

### 初始条件

u[int(.5 / dy): int(1 / dy + 1), int(.5 / dx):int(1 / dx + 1)] = 2

#%% 例子1:raw python
%%timeit
u = numpy.ones((ny, nx))
u[int(.5 / dy): int(1 / dy + 1), int(.5 / dx):int(1 / dx + 1)] = 2

for n in range(nt + 1): ##loop across number of time steps
    un = u.copy()
    row, col = u.shape
    for j in range(1, row):
        for i in range(1, col):
            u[j, i] = (un[j, i] - (c * dt / dx * 
                                  (un[j, i] - un[j, i - 1])) - 
                                  (c * dt / dy * 
                                   (un[j, i] - un[j - 1, i])))
            u[0, :] = 1
            u[-1, :] = 1
            u[:, 0] = 1
            u[:, -1] = 1


#%% 例子2:python with numpy
%%timeit
u = numpy.ones((ny, nx))
u[int(.5 / dy): int(1 / dy + 1), int(.5 / dx):int(1 / dx + 1)] = 2

for n in range(nt + 1): ##loop across number of time steps
    un = u.copy()
    u[1:, 1:] = (un[1:, 1:] - (c * dt / dx * (un[1:, 1:] - un[1:, 0:-1])) -
                              (c * dt / dy * (un[1:, 1:] - un[0:-1, 1:])))
    u[0, :] = 1
    u[-1, :] = 1
    u[:, 0] = 1
    u[:, -1] = 1
  1. 以上两个例子的结果如下(我的设备是Macbook air M2,不同机子的运行时间不一样的)
    • 例子1:1.63 s ± 31.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    • 例子2:3.32 ms ± 39.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

07 Step 5: 2-D Linear Convection 2维线性扩散

071 简单的有限差分

  1. 这一步很简单,就是把原来的1D变成了现在的2D,方程如下:
    ∂ u ∂ t + c ∂ u ∂ x + c ∂ u ∂ y = 0 \frac{\partial u}{\partial t}+c\frac{\partial u}{\partial x} + c\frac{\partial u}{\partial y} = 0 tu+cxu+cyu=0
    u i , j n + 1 − u i , j n Δ t + c u i , j n − u i − 1 , j n Δ x + c u i , j n − u i , j − 1 n Δ y = 0 \frac{u_{i,j}^{n+1}-u_{i,j}^n}{\Delta t} + c\frac{u_{i, j}^n-u_{i-1,j}^n}{\Delta x} + c\frac{u_{i,j}^n-u_{i,j-1}^n}{\Delta y}=0 Δtui,jn+1ui,jn+cΔxui,jnui1,jn+cΔyui,jnui,j1n=0
  2. 其中,i表示x方向的index,j表示y方向的index,n表示时间上的index
  3. 例子给的初始条件是: u ( x , y ) = { 2  for 0.5 ≤ x , y ≤ 1 1  for everywhere else u(x,y) = \begin{cases} \begin{matrix} 2\ \text{for} & 0.5 \leq x, y \leq 1 \cr 1\ \text{for} & \text{everywhere else}\end{matrix}\end{cases} u(x,y)={2 for1 for0.5x,y1everywhere else
  4. 边界条件: u = 1  for  { x = 0 ,   2 y = 0 ,   2 u = 1\ \text{for } \begin{cases} \begin{matrix} x = 0,\ 2 \cr y = 0,\ 2 \end{matrix}\end{cases} u=1 for {x=0, 2y=0, 2
  5. 原文给了初始条件的3D图,还是很赞的3D图
  6. 代码如下:
from mpl_toolkits.mplot3d import Axes3D    ##New Library required for projected 3d plots

import numpy
from matplotlib import pyplot, cm
%matplotlib inline

###variable declarations
nx = 81
ny = 81
nt = 100
c = 1
dx = 2 / (nx - 1)
dy = 2 / (ny - 1)
sigma = .2
dt = sigma * dx

x = numpy.linspace(0, 2, nx)
y = numpy.linspace(0, 2, ny)

u = numpy.ones((ny, nx)) ##create a 1xn vector of 1's
un = numpy.ones((ny, nx)) ##

###Assign initial conditions
##set hat function I.C. : u(.5<=x<=1 && .5<=y<=1 ) is 2
u[int(.5 / dy):int(1 / dy + 1),int(.5 / dx):int(1 / dx + 1)] = 2 

###Plot Initial Condition
##the figsize parameter can be used to produce different sized images
fig = pyplot.figure(figsize=(11, 7), dpi=100)
ax = fig.gca(projection='3d')                      
X, Y = numpy.meshgrid(x, y)                            
surf = ax.plot_surface(X, Y, u[:], cmap=cm.viridis)

# array operation
u = numpy.ones((ny, nx))
u[int(.5 / dy):int(1 / dy + 1), int(.5 / dx):int(1 / dx + 1)] = 2

for n in range(nt + 1): ##loop across number of time steps
    un = u.copy()
    u[1:, 1:] = (un[1:, 1:] - (c * dt / dx * (un[1:, 1:] - un[1:, :-1])) -(c * dt / dy * (un[1:, 1:] - un[:-1, 1:])))
    u[0, :] = 1
    u[-1, :] = 1
    u[:, 0] = 1
    u[:, -1] = 1

# plot answer
fig = pyplot.figure(figsize=(11, 7), dpi=100)
ax = fig.gca(projection='3d')
surf2 = ax.plot_surface(X, Y, u[:], cmap=cm.viridis)

072-关于绘制3D图

  1. 3D图库代码:from mpl_toolkits.mplot3d import Axes3D
  2. 创建画布,figsize用来限定尺寸,dpi表示图片精度:fig = pyplot.figure(figsize=(11, 7), dpi=100)
  3. 创建轴,projection表示3d还是2d:ax = fig.gca(projection='3d')
  4. 将散点展开成网格点,这是画3d图的基础,因为单看x和y都是一组列向量or行向量:X, Y = numpy.meshgrid(x, y)
  5. 画图:surf = ax.plot_surface(X, Y, u[:], cmap=cm.viridis)
  6. 画轴标签:ax.set_xlabel('$x$') ax.set_ylabel('$y$');

08-Step 6: 2-D Convection 2维非线性扩散

  1. 这几章套路都是一样的,方程形式如下:
    ∂ u ∂ t + u ∂ u ∂ x + v ∂ u ∂ y = 0 \frac{\partial u}{\partial t} + u \frac{\partial u}{\partial x} + v \frac{\partial u}{\partial y} = 0 tu+uxu+vyu=0

∂ v ∂ t + u ∂ v ∂ x + v ∂ v ∂ y = 0 \frac{\partial v}{\partial t} + u \frac{\partial v}{\partial x} + v \frac{\partial v}{\partial y} = 0 tv+uxv+vyv=0
2. 离散与上一个step一样:
u i , j n + 1 − u i , j n Δ t + u i , j n u i , j n − u i − 1 , j n Δ x + v i , j n u i , j n − u i , j − 1 n Δ y = 0 \frac{u_{i,j}^{n+1}-u_{i,j}^n}{\Delta t} + u_{i,j}^n \frac{u_{i,j}^n-u_{i-1,j}^n}{\Delta x} + v_{i,j}^n \frac{u_{i,j}^n-u_{i,j-1}^n}{\Delta y} = 0 Δtui,jn+1ui,jn+ui,jnΔxui,jnui1,jn+vi,jnΔyui,jnui,j1n=0

v i , j n + 1 − v i , j n Δ t + u i , j n v i , j n − v i − 1 , j n Δ x + v i , j n v i , j n − v i , j − 1 n Δ y = 0 \frac{v_{i,j}^{n+1}-v_{i,j}^n}{\Delta t} + u_{i,j}^n \frac{v_{i,j}^n-v_{i-1,j}^n}{\Delta x} + v_{i,j}^n \frac{v_{i,j}^n-v_{i,j-1}^n}{\Delta y} = 0 Δtvi,jn+1vi,jn+ui,jnΔxvi,jnvi1,jn+vi,jnΔyvi,jnvi,j1n=0
3. 最终代码形式:
u i , j n + 1 = u i , j n − u i , j Δ t Δ x ( u i , j n − u i − 1 , j n ) − v i , j n Δ t Δ y ( u i , j n − u i , j − 1 n ) u_{i,j}^{n+1} = u_{i,j}^n - u_{i,j} \frac{\Delta t}{\Delta x} (u_{i,j}^n-u_{i-1,j}^n) - v_{i,j}^n \frac{\Delta t}{\Delta y} (u_{i,j}^n-u_{i,j-1}^n) ui,jn+1=ui,jnui,jΔxΔt(ui,jnui1,jn)vi,jnΔyΔt(ui,jnui,j1n)

v i , j n + 1 = v i , j n − u i , j Δ t Δ x ( v i , j n − v i − 1 , j n ) − v i , j n Δ t Δ y ( v i , j n − v i , j − 1 n ) v_{i,j}^{n+1} = v_{i,j}^n - u_{i,j} \frac{\Delta t}{\Delta x} (v_{i,j}^n-v_{i-1,j}^n) - v_{i,j}^n \frac{\Delta t}{\Delta y} (v_{i,j}^n-v_{i,j-1}^n) vi,jn+1=vi,jnui,jΔxΔt(vi,jnvi1,jn)vi,jnΔyΔt(vi,jnvi,j1n)
4. 初始条件和上一个step一样: u ,   v   = { 2 for  x , y ∈ ( 0.5 , 1 ) × ( 0.5 , 1 ) 1 everywhere else u,\ v\ = \begin{cases}\begin{matrix} 2 & \text{for } x,y \in (0.5, 1)\times(0.5,1) \cr 1 & \text{everywhere else} \end{matrix}\end{cases} u, v ={21for x,y(0.5,1)×(0.5,1)everywhere else
5. 边界条件和上一个step一样: u = 1 ,   v = 1  for  { x = 0 , 2 y = 0 , 2 u = 1,\ v = 1 \text{ for } \begin{cases} \begin{matrix}x=0,2\cr y=0,2 \end{matrix}\end{cases} u=1, v=1 for {x=0,2y=0,2
6. 这里和上一届一样,就改了改这里

for n in range(nt + 1): ##loop across number of time steps
    un = u.copy()
    vn = v.copy()
    u[1:, 1:] = (un[1:, 1:] - (un[1:, 1:] * c * dt / dx * (un[1:, 1:] - un[1:, :-1])) -vn[1:, 1:] * c * dt / dy * (un[1:, 1:] - un[:-1, 1:]))
    v[1:, 1:] = (vn[1:, 1:] - (un[1:, 1:] * c * dt / dx * (vn[1:, 1:] - vn[1:, :-1])) -vn[1:, 1:] * c * dt / dy * (vn[1:, 1:] - vn[:-1, 1:]))
    
    u[0, :] = 1
    u[-1, :] = 1
    u[:, 0] = 1
    u[:, -1] = 1
    
    v[0, :] = 1
    v[-1, :] = 1
    v[:, 0] = 1
    v[:, -1] = 1

09-Step 7: 2D Diffusion

  1. 这个也和一维扩散差不多,就是加了一维罢了,方程形式如下:
    ∂ u ∂ t = ν ∂ 2 u ∂ x 2 + ν ∂ 2 u ∂ y 2 \frac{\partial u}{\partial t} = \nu \frac{\partial ^2 u}{\partial x^2} + \nu \frac{\partial ^2 u}{\partial y^2} tu=νx22u+νy22u
  2. 离散后:
    u i , j n + 1 − u i , j n Δ t = ν u i + 1 , j n − 2 u i , j n + u i − 1 , j n Δ x 2 + ν u i , j + 1 n − 2 u i , j n + u i , j − 1 n Δ y 2 \frac{u_{i,j}^{n+1} - u_{i,j}^n}{\Delta t} = \nu \frac{u_{i+1,j}^n - 2 u_{i,j}^n + u_{i-1,j}^n}{\Delta x^2} + \nu \frac{u_{i,j+1}^n-2 u_{i,j}^n + u_{i,j-1}^n}{\Delta y^2} Δtui,jn+1ui,jn=νΔx2ui+1,jn2ui,jn+ui1,jn+νΔy2ui,j+1n2ui,jn+ui,j1n
    u i , j n + 1 = u i , j n + ν Δ t Δ x 2 ( u i + 1 , j n − 2 u i , j n + u i − 1 , j n ) + ν Δ t Δ y 2 ( u i , j + 1 n − 2 u i , j n + u i , j − 1 n ) \begin{split} u_{i,j}^{n+1} = u_{i,j}^n &+ \frac{\nu \Delta t}{\Delta x^2}(u_{i+1,j}^n - 2 u_{i,j}^n + u_{i-1,j}^n) + \frac{\nu \Delta t}{\Delta y^2}(u_{i,j+1}^n-2 u_{i,j}^n + u_{i,j-1}^n) \end{split} ui,jn+1=ui,jn+Δx2νΔt(ui+1,jn2ui,jn+ui1,jn)+Δy2νΔt(ui,j+1n2ui,jn+ui,j1n)
  3. 代码如下:
###Run through nt timesteps
def diffuse(nt):
    u[int(.5 / dy):int(1 / dy + 1),int(.5 / dx):int(1 / dx + 1)] = 2  
    
    for n in range(nt + 1): 
        un = u.copy()
        u[1:-1, 1:-1] = (un[1:-1,1:-1] + nu * dt / dx**2 * (un[1:-1, 2:] - 2 * un[1:-1, 1:-1] + un[1:-1, 0:-2]) + nu * dt / dy**2 *(un[2:,1: -1] - 2 * un[1:-1, 1:-1] + un[0:-2, 1:-1]))
        u[0, :] = 1
        u[-1, :] = 1
        u[:, 0] = 1
        u[:, -1] = 1

    
    fig = pyplot.figure()
    ax = fig.gca(projection='3d')
    surf = ax.plot_surface(X, Y, u[:], rstride=1, cstride=1, cmap=cm.viridis,
        linewidth=0, antialiased=True)
    ax.set_zlim(1, 2.5)
    ax.set_xlabel('$x$')
    ax.set_ylabel('$y$');

10-Step 8: Burgers’ Equation in 2D

  1. (如果你的想法和我一样,我觉得应该算入门了)感觉step5-8都差不多,就是先对方程进行离散,然后绘制网格+初始条件边界条件,最后用numpy array operation递推
  2. 作者说,第八步的Burgers方程是一个里程碑,但是对于Burgers的解并不是光滑的,而是离散的,比如“激波”
  3. 同理,原方程形式:
    ∂ u ∂ t + u ∂ u ∂ x + v ∂ u ∂ y = ν    ( ∂ 2 u ∂ x 2 + ∂ 2 u ∂ y 2 ) \frac{\partial u}{\partial t} + u \frac{\partial u}{\partial x} + v \frac{\partial u}{\partial y} = \nu \; \left(\frac{\partial ^2 u}{\partial x^2} + \frac{\partial ^2 u}{\partial y^2}\right) tu+uxu+vyu=ν(x22u+y22u)

∂ v ∂ t + u ∂ v ∂ x + v ∂ v ∂ y = ν    ( ∂ 2 v ∂ x 2 + ∂ 2 v ∂ y 2 ) \frac{\partial v}{\partial t} + u \frac{\partial v}{\partial x} + v \frac{\partial v}{\partial y} = \nu \; \left(\frac{\partial ^2 v}{\partial x^2} + \frac{\partial ^2 v}{\partial y^2}\right) tv+uxv+vyv=ν(x22v+y22v)
4. 一样地离散:
u i , j n + 1 − u i , j n Δ t + u i , j n u i , j n − u i − 1 , j n Δ x + v i , j n u i , j n − u i , j − 1 n Δ y = ν ( u i + 1 , j n − 2 u i , j n + u i − 1 , j n Δ x 2 + u i , j + 1 n − 2 u i , j n + u i , j − 1 n Δ y 2 ) \begin{split} & \frac{u_{i,j}^{n+1} - u_{i,j}^n}{\Delta t} + u_{i,j}^n \frac{u_{i,j}^n-u_{i-1,j}^n}{\Delta x} + v_{i,j}^n \frac{u_{i,j}^n - u_{i,j-1}^n}{\Delta y} = \nu \left( \frac{u_{i+1,j}^n - 2u_{i,j}^n+u_{i-1,j}^n}{\Delta x^2} + \frac{u_{i,j+1}^n - 2u_{i,j}^n + u_{i,j-1}^n}{\Delta y^2} \right) \end{split} Δtui,jn+1ui,jn+ui,jnΔxui,jnui1,jn+vi,jnΔyui,jnui,j1n=ν(Δx2ui+1,jn2ui,jn+ui1,jn+Δy2ui,j+1n2ui,jn+ui,j1n)
v i , j n + 1 − v i , j n Δ t + u i , j n v i , j n − v i − 1 , j n Δ x + v i , j n v i , j n − v i , j − 1 n Δ y = ν ( v i + 1 , j n − 2 v i , j n + v i − 1 , j n Δ x 2 + v i , j + 1 n − 2 v i , j n + v i , j − 1 n Δ y 2 ) \begin{split} & \frac{v_{i,j}^{n+1} - v_{i,j}^n}{\Delta t} + u_{i,j}^n \frac{v_{i,j}^n-v_{i-1,j}^n}{\Delta x} + v_{i,j}^n \frac{v_{i,j}^n - v_{i,j-1}^n}{\Delta y} = \nu \left( \frac{v_{i+1,j}^n - 2v_{i,j}^n+v_{i-1,j}^n}{\Delta x^2} + \frac{v_{i,j+1}^n - 2v_{i,j}^n + v_{i,j-1}^n}{\Delta y^2} \right) \end{split} Δtvi,jn+1vi,jn+ui,jnΔxvi,jnvi1,jn+vi,jnΔyvi,jnvi,j1n=ν(Δx2vi+1,jn2vi,jn+vi1,jn+Δy2vi,j+1n2vi,jn+vi,j1n)
5. 代码如下:

import numpy
from matplotlib import pyplot, cm
from mpl_toolkits.mplot3d import Axes3D
%matplotlib inline

###variable declarations
nx = 41
ny = 41
nt = 120
c = 1
dx = 2 / (nx - 1)
dy = 2 / (ny - 1)
sigma = .0009
nu = 0.01
dt = sigma * dx * dy / nu


x = numpy.linspace(0, 2, nx)
y = numpy.linspace(0, 2, ny)

u = numpy.ones((ny, nx))  # create a 1xn vector of 1's
v = numpy.ones((ny, nx))
un = numpy.ones((ny, nx)) 
vn = numpy.ones((ny, nx))
comb = numpy.ones((ny, nx))

###Assign initial conditions

##set hat function I.C. : u(.5<=x<=1 && .5<=y<=1 ) is 2
u[int(.5 / dy):int(1 / dy + 1),int(.5 / dx):int(1 / dx + 1)] = 2 
##set hat function I.C. : u(.5<=x<=1 && .5<=y<=1 ) is 2
v[int(.5 / dy):int(1 / dy + 1),int(.5 / dx):int(1 / dx + 1)] = 2

###(plot ICs)
fig = pyplot.figure(figsize=(11, 7), dpi=100)
ax = fig.gca(projection='3d')
X, Y = numpy.meshgrid(x, y)
ax.plot_surface(X, Y, u[:], cmap=cm.viridis, rstride=1, cstride=1)
ax.plot_surface(X, Y, v[:], cmap=cm.viridis, rstride=1, cstride=1)
ax.set_xlabel('$x$')
ax.set_ylabel('$y$');

for n in range(nt + 1): ##loop across number of time steps
    un = u.copy()
    vn = v.copy()

    u[1:-1, 1:-1] = (un[1:-1, 1:-1] -
                     dt / dx * un[1:-1, 1:-1] * 
                     (un[1:-1, 1:-1] - un[1:-1, 0:-2]) - 
                     dt / dy * vn[1:-1, 1:-1] * 
                     (un[1:-1, 1:-1] - un[0:-2, 1:-1]) + 
                     nu * dt / dx**2 * 
                     (un[1:-1,2:] - 2 * un[1:-1, 1:-1] + un[1:-1, 0:-2]) + 
                     nu * 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] - 
                     dt / dx * un[1:-1, 1:-1] *
                     (vn[1:-1, 1:-1] - vn[1:-1, 0:-2]) -
                     dt / dy * vn[1:-1, 1:-1] * 
                    (vn[1:-1, 1:-1] - vn[0:-2, 1:-1]) + 
                     nu * dt / dx**2 * 
                     (vn[1:-1, 2:] - 2 * vn[1:-1, 1:-1] + vn[1:-1, 0:-2]) +
                     nu * dt / dy**2 *
                     (vn[2:, 1:-1] - 2 * vn[1:-1, 1:-1] + vn[0:-2, 1:-1]))
     
    u[0, :] = 1
    u[-1, :] = 1
    u[:, 0] = 1
    u[:, -1] = 1
    
    v[0, :] = 1
    v[-1, :] = 1
    v[:, 0] = 1
    v[:, -1] = 1

fig = pyplot.figure(figsize=(11, 7), dpi=100)
ax = fig.gca(projection='3d')
X, Y = numpy.meshgrid(x, y)
ax.plot_surface(X, Y, u, cmap=cm.viridis, rstride=1, cstride=1)
ax.plot_surface(X, Y, v, cmap=cm.viridis, rstride=1, cstride=1)
ax.set_xlabel('$x$')
ax.set_ylabel('$y$');
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值