流體模擬基礎1


1,散度 鼠標右鍵打開(高清圖)

 

 1.1 探討1D 情況下的advection

(來自Fluid simulation for computer graphic - Robert Bridson)

 

初始化一些變量:,

其中dt 按照文章寫的:

 

import numpy as np
from matplotlib import pyplot
import time,sys

nx = 100
dx = 2/(nx-1)
nt = 100  #25 steps
u  = 1   #assume advection speed = 1
dt = dx/2


q = np.array([0.2 for x in range(nx)])

############ our init condition#######################################
# THIS CONDITION FROM PAGE-41 Robert Bridson
for x in range(2,11,1):
    q[x] = x/10.0
q[10:19] = (q[2:11])[::-1]
######################################################################

 

這個是初值條件:

pyplot.plot(np.linspace(0,nx,nx),q)
pyplot.show()
pyplot.close()

 

 

 接下來先用 這個方法做:

 

def eulerian_advection():
    rhq = q.copy()  # this function compute THIS, and return this!
    qn = np.zeros(nx)
    for step in range(nt):
        # every time step we need update our READY-Q: qn
        qn = rhq.copy()
        for i in range(1,nx):
            rhq[i] = qn[i] - u * dt / dx* (qn[i] - qn[i-1])
    return rhq

pyplot.plot(np.linspace(0,nx,nx),q)
pyplot.show()
pyplot.close()

 

然后把這個寫成人類可讀的 py易讀:

def eulerian_advection_very_numpy():
    rhq = q.copy()  # this function compute THIS, and return this!
    qn = np.zeros(nx)
    for step in range(nt):
        # every time step we need update our READY-Q: qn
        qn = rhq.copy()
        rhq[1:] = qn[1:] - u * dt / dx *(qn[1:] - qn[0:-1])
    return rhq
pyplot.plot(np.linspace(0,nx,nx),q)
pyplot.show()
pyplot.close()

 這個公式經過100 time step size步帶來的效果,

 

 使用semi-lagrangian:

 

# fluid simulation computer graphics [page 33]
def semi_lagrangian():
    rhq = q.copy()  # this function compute THIS, and return this!
    qn = np.zeros(nx)

    for step in range(nt):
        qn = rhq.copy()

        for i in range(1, nx-1):
            xj = (i-1) * dx
            xg = i*dx
            xp = xg - dt * u
            w = (xp-xj)/dx
            qj  = qn[i-1]
            qj1 = qn[i+1]

            rhq[i] = (1-w) * qj + w * qj1
        plot_data(rhq)
    return rhq

semi_lagrangian()

 1.2 signed distance

假設速度是vector(0,1,0) 會出現下面的可視化:

 

 

 

 

2,如何在Houdini里解 2-D Linear Convection

離散完之后:

 

 

 初始條件:

Boundry地方全為0

中間設置了一些 數值.不過是把u映射到y 的高度

 

 

int row = chi("ny");
int column = chi("nx");
float c = 1;
float dx = 2.0 / float(row - 1);
float dy = 2.0 / float(column - 1);
float sigma = .2;
float dt = sigma * dx;


for(int j=0; j< row ;j++)
{
    for(int i=0; i< column ; i++)
    {
        int pt =  j * row + i;
        float u = point(0,"u",pt);
        
        // partial u/x
        int pt_x_next = j * row + i-1;
        float x_next_u = point(0,"u",pt_x_next);
        float partial_u_x = u - x_next_u;
        
        // partial u/y
        int pt_y_next = (j-1)*row + i;
        float y_next_u = point(0,"u",pt_y_next);
        float partial_u_y = u - y_next_u;
        
        
        float newu = u - c * dt/dx * ( partial_u_x) - c * dt/dy *( partial_u_y);
        setpointattrib(0,"u",pt,newu);
    }
}
code detail 模式

 

 過了一些幀

 

 

 

 Diffusion 方程:做完感覺是個高斯模糊。。。。

 

int row = chi("ny");
int column = chi("nx");
float c = 16;
float dx = 2.0 / float(row - 1);
float dy = 2.0 / float(column - 1);
float sigma = .05;
float dt = sigma * dx;
float viscosity = 0.05;

for(int j=1; j< row ;j++)
{
    for(int i=1; i< column ; i++)
    {
        int pt =  j * row + i;
        float u = point(0,"u",pt);
        
        
        int uxnext  = j * row + i+1;
        int uxfront = j * row + i-1;
        
        int uynext = (j+1)*row + i;
        int uyfront = (j-1)*row + i;
        
        
        // u/x 二階偏導數
        float uxnext_val = point(0,"u",uxnext);
        float uxfront_val = point(0,"u",uxfront);
        float partial_uu_xx = uxnext_val - 2 * u + uxfront_val;
        
        // u/y 二階偏導數
        float uynext_val = point(0,"u",uynext);
        float uyfront_val = point(0,"u",uyfront);
        float partial_uu_yy = uynext_val - 2 * u + uyfront_val;
        
 
        
        float newu = u + viscosity * dt / (dx*dx) * partial_uu_xx + viscosity*dt / (dy*dy) * partial_uu_yy ;
        
        
    
        setpointattrib(geoself(),"u",pt,newu);
    }
}
View Code

 

 

 

 第一幀:

 

過了60幀:

 

 

 

 

 

歐拉方法,K階泰勒方法, 龍格-庫塔RK2(中點midpoint), RK4

歐拉向前公式: 

 

歐拉向前步進法 精度測試,事實上可以用托馬斯微積分給的 改進歐拉法(梯形法) 比現在這個要精確的多。

在[0,1]區間,看到n的步伐增加,對y的預測更加准確。

import numpy
from matplotlib import pyplot

def euler_step(t, y, h, yPrimFunction):
    """
    :param t: 當前時間t
    :param y: 當前值y
    :param h: 當前步長h
    :return: 時間上t+h的近似解
    """
    val =  y + h * yPrimFunction(t, y)
    return val

def euler(space, y0, n, yPrime):
    """
    :param space: [x 軸向上的區間]
    :param y0:  初值y0
    :param n:   步伐總值
    :return: [( t array) (y array)]
    """

    h = (space[1] - space[0]) / float(n)
    tArray = numpy.linspace(space[0], space[1], n)
    yArray = numpy.zeros(n)
    yArray[0] = y0
    
    for i in range(n-1):
        yArray[i+1] = euler_step(tArray[i], yArray[i], h, yPrime)
    return numpy.array((tArray,yArray))


func = lambda t, y : t * y + t*t*t
mapped_10 = euler([0, 1], 1, 10, func )
mapped_20 = euler([0, 1], 1, 20, func )
mapped_30 = euler([0, 1], 1, 30, func )
mapped_40 = euler([0, 1], 1, 40, func )

def plot_simple():
    pyplot.plot(mapped_10[0],mapped_10[1])  ##Plot the results
    pyplot.plot(mapped_20[0],mapped_20[1])  ##Plot the results
    pyplot.show()

def plot_complex():
    fig, ax = pyplot.subplots()
    ax.plot(mapped_10[0], mapped_10[1], label="n=10")
    ax.plot(mapped_20[0], mapped_20[1], label="n=20")
    ax.plot(mapped_30[0], mapped_30[1], label="n=30")
    ax.plot(mapped_40[0], mapped_40[1], label="n=40")
    ax.legend(loc=2)  # upper left corner
    ax.set_xlabel('t')
    ax.set_ylabel('y')
    ax.set_title("Euler Step method for: y'= t*y + t^3 ")
    pyplot.show()

plot_complex()
View Code

 

根據斜率場預測下一個值的除了歐拉法 還有幾個出名的方法。

1, K階泰勒方法 ,一階的泰勒方法正是 歐拉方法。

    K階的泰勒方法有個缺點,就是必須把K階導數求出來

    圍繞泰勒方法,離散方法: 求導數,ODE, PDE

    而ODE的離散方法 和 導數的離散方法,仔細觀察就是從泰勒定理里 完全剝離出來的

 

2,但是RK2 RK3 RK4  完全是不用把不用知道 f'' f''' ... 的情況下把K階的方法求出來,

     RK4 全局誤差和h^4 成正比. 流體力學用到RK4 已經算出很高的精度了

 

3,還有更高級的 可變步長方法。

 

泊松方程

 

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

nx = 100
ny = 100

xmin = 0
xmax = 2

ymin = 0
ymax = 1

dx = (xmax - xmin) / (nx - 1)
dy = (ymax - ymin) / (ny - 1)

print(dx, dy)

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

x = numpy.linspace(xmin, xmax, nx)
y = numpy.linspace(ymin, ymax, ny)

# boundary condition for p
p[0, :] = 0  # p = 0 @ y = 1      最頂一行
p[ny - 1, :] = 0  # p = 0 @ y = 0     最底一行

p[:, 0] = 0  # p = 0 @ x = 0     左邊一列
p[:, nx - 1] = 0  # p = 0 @ x = 2     右邊一列

# print(p)
# init condition for b

b[:, int(ny / 2 - 10):int(ny / 2 + 10)] = 100
b[int(ny / 2 - 10):int(ny / 2 + 10):] = 100

# print(b)


square_dx = dx * dx
square_dy = dy * dy

nt = 200


def plot2D(x, y, p, frame):
    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, p[:], rstride=1, cstride=1, cmap=cm.viridis,
                           linewidth=0, antialiased=False)
    ax.view_init(30, 225)
    ax.set_xlabel('$x$')
    ax.set_ylabel('$y$')
    fig.savefig('./imgs/Laplace2d.' + ('00000' + str(frame))[-4:] + '.png')
    # pyplot.close()
    pyplot.show()


for it in range(nt):
    pre_p = p.copy()

    p[1:-1, 1:-1] = ((pre_p[1:-1, 2:] + pre_p[1:-1, 0:-2]) * dy * dy +
                     (pre_p[2:, 1:-1] + pre_p[:-2, 1:-1]) * dx * dx -
                     b[1:-1, 1:-1] * dx * dx * dy * dy) / (2 * (dx * dx + dy * dy))

    p[0, :] = 0  # p = 0 @ y = 1      最頂一行
    p[ny - 1, :] = 0  # p = 0 @ y = 0     最底一行
    p[:, 0] = 0  # p = 0 @ x = 0     左邊一列
    p[:, nx - 1] = 0  # p = 0 @ x = 2     右邊一列
    plot2D(x, y, p, it)
View Code

 

迭代100次的過程 

REF:

http://nbviewer.jupyter.org/github/barbagroup/CFDPython/blob/master/lessons/07_Step_5.ipynb

https://en.wikipedia.org/wiki/Euler_method

https://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM