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); } }
過了一些幀
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); } }
第一幀:
過了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()
根據斜率場預測下一個值的除了歐拉法 還有幾個出名的方法。
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)
迭代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