CFD Python:求解Navier-Stokes方程的12個步驟(5)

ieic5tq8ymk e1668923225194

(本文經Prof. Lorena A. Barba授權轉載翻譯自Prof. Lorena A. Barba的教材”12 Steps to Navier-Stokes”,原文鏈結請參照底下參考資料)

Text provided under a Creative Commons Attribution license, CC-BY. All code is made available under the FSF-approved BSD-3 license. (c) Lorena A. Barba, Gilbert F. Forsyth 2017. Thanks to NSF for support via CAREER award #1149784.

CFD Python:求解Navier-Stokes方程的12個步驟(1)
CFD Python:求解Navier-Stokes方程的12個步驟(2)
CFD Python:求解Navier-Stokes方程的12個步驟(3)
CFD Python:求解Navier-Stokes方程的12個步驟(4)
CFD Python:求解Navier-Stokes方程的12個步驟(5)
CFD Python:求解Navier-Stokes方程的12個步驟(6)
CFD Python:求解Navier-Stokes方程的12個步驟(7)
CFD Python:求解Navier-Stokes方程的12個步驟(8)
CFD Python:求解Navier-Stokes方程的12個步驟(9)
CFD Python:求解Navier-Stokes方程的12個步驟(10)
CFD Python:求解Navier-Stokes方程的12個步驟(11)
CFD Python:求解Navier-Stokes方程的12個步驟(12)

到目前為止,全部的練習都是在一維空間。我們可以從一維例題學到許多,不過讓我們朝下個目標邁進:二維問題。

在下面的練習中,你將會把前四個步驟擴展至二維問題。要將一維有限差分公式運用至二維或三維,只需要應用這個定義:x的偏導數只是當y保持定量時沿著x方向的變量而已。

在二維空間中,一個矩形(均勻)網格透過下列座標點定義:

x_i = x_0 +i \Delta x

y_i = y_0 +i \Delta y

現在定義u_{i,j} = u(x_i,y_j),針對任一變量x, y來應用有限差分公式,分別作用於i索引與j索引。所有導數都基於作用在網格點u_{i,j}周圍的二維泰勒展開式。

因此,對於x方向上的一維偏導數而言,有限差分式子如下:

\frac{\partial u}{\partial x}\biggr\rvert_{i,j} = \frac{u_{i+1,j}-u_{i,j}}{\Delta x}+\mathcal{O}(\Delta x)

而在y方向上也有類似的公式。因此,我們可以寫出步驟5至12前向差分、後向差分以及中央差分的公式。讓我們開始吧!

步驟5:二維線性對流

二維線性對流方程如下:

\frac{\partial u}{\partial t}+c\frac{\partial u}{\partial x} + c\frac{\partial u}{\partial y} = 0

這確實與我們一維線性對流方程相同,撇除我們擁有兩個需要隨著時間推進的空間項。與先前一樣,時間步長使用前向差分離散,空間項使用後向差分離散。

在一維的案例實作,我們使用i作為下標來表示空間項變化(e.g. u_{i}^n-u_{i-1}^n)。現在我們必須考慮二維,因此添加第二個下標j來表示二維空間資訊。

這裡一樣使用i作為x方向的索引,而j下標則用來追蹤y方向。把這個銘記在心,偏微分方程的離散將會變得相對直覺許多。

\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

跟之前一樣,可用下式求解未知項:

u_{i,j}^{n+1} = u_{i,j}^n-c \frac{\Delta t}{\Delta x}(u_{i,j}^n-u_{i-1,j}^n)-c \frac{\Delta t}{\Delta y}(u_{i,j}^n-u_{i,j-1}^n)

我們將會搭配下述初始條件來求解這個方程式:

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 = 1\ \text{for } \begin{cases} \begin{matrix} x = 0,\ 2 \cr y = 0,\ 2 \end{matrix}\end{cases}

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)

1

3D繪圖註記

為了繪製3D投影結果,請確保您已添加Axes3D函式庫。

from mpl_toolkits.mplot3d import Axes3D

實際的繪圖指令比簡單2D繪圖還要複雜一些。

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

這裡的第一行指令用來初始化繪圖視窗。figsize指令與dpi指令為額外選項,只是用來指定圖形尺寸與解析度。你可以忽略他們,但你仍需要底下指令:

fig = pyplot.figure()

下一行將軸標籤’ax’指定給繪圖視窗並表示這會是個3D投影繪圖。最後一行使用下列指令:

plot_surface()

這一行等同一般繪圖指令,但它使用X與Y網格點數據來表示資料點位置。

註記

傳給plot_surface的X值與Y值並不是X與Y的一維向量。為了使用matplotlibs的3D繪圖功能,你必須產生基於x值與y值的網格且該網格對應於繪圖窗口中的每個座標。該網格可用numpy功能meshgrid產生。

X, Y = numpy.meshgrid(x, y)

二維空間迭代

為了評估二維中的波動,需要使用涵蓋i與j的巢狀迴圈。由於Python並不是編譯語言,執行多重迴圈程式碼的速度將會明顯下降。首先,先用來嘗試評估二維對流的程式碼並看看會產生什麼結果。

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

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

NS 5 2

矩陣操作

這裡同樣有個二維對流程式碼,然而這段程式碼並不是使用巢狀迴圈,而是利用矩陣操作來執行同樣計算。

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

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

NS 5 3

參考資料

  1. 12 steps to Navier–Stokes: Step 5: 2-D Linear ConvectionLorena A. Barba

創用 CC 授權條款
本著作係採用創用 CC 姓名標示 4.0 國際 授權條款授權.

Leave a Comment

發佈留言必須填寫的電子郵件地址不會公開。