上一篇文章寫了正方形網格的情形,實際計算中常常用到非等距矩形網格,因此我把上個代碼改成了非等距形式。改成非等距形式後,五點差分法將泊松方程化成方程組時,公式形式和正方形形式稍微不一樣,我推了一下,沒查任何文獻,不保證正確。方程左邊是f,右邊是原函數二階導數的差分形式。將u[i,j]移到左邊,除掉係數就得到u的方程組。
代碼如下
import numpy as np
import matplotlib.pyplot as plt
import math
from pylab import *
from mpl_toolkits.mplot3d import axes3d
def fine2(grid0,hx0,hy0): #化成細網格
nx_grid2 = int((hx0.size)*2 + 1) #x 方向粗化後網格數量
ny_grid2 = int((hy0.size)*2 + 1)
grid2 = np.zeros((ny_grid2,nx_grid2), dtype = float)
hx2,hy2,x2,y2 = hx_level(nx_grid2-1)
for i in range(1, hx0.size+1):
i2 = i*2
for j in range(1, hy0.size+1): #賦值中間的網格
j2 = j*2
grid2[j2,i2] = grid0[j,i]
grid2[j2,i2-1] = grid0[j,i]*(hx2[i2-2]/(hx2[i2-1]+hx2[i2-1]))+grid0[j,i-1]*(hx2[i2-1]/(hx2[i2-2]+hx2[i2-1]))
grid2[j2-1,i2] = grid0[j,i]*(hy2[j2-2]/(hy2[j2-2]+hy2[j2-1])) +grid0[j-1,i]*(hy2[j2-1]/(hy2[j2-2]+hy2[j2-1]))
totalweight = 1./hx2[i2-1]+1./hx2[i2-2]+1./hy2[j2-1]+1./hy2[j2-2]
weight2 = 1./hx2[i2-1]/totalweight
weight3 = 1./hy2[j2-2]/totalweight
weight1 = 1./hx2[i2-2]/totalweight
weight4 = 1./hy2[j2-1]/totalweight
grid2[j2-1,i2-1] = grid2[j2-1,i2-2]*weight1+grid2[j2-1,i2]*weight2+grid2[j2-2,i2-1]*weight3+grid2[j2,i2-1]*weight4
for i in range(1, hx0.size+1):#賦值邊界
i2 = i*2
grid2[0,2*i] = grid0[0,i]
grid2[0,2*i-1] = hx2[i2-1]/(hx2[i2-1]+hx2[i2-2])*grid0[0,i-1]+hx2[i2-2]/(hx2[i2-1]+hx2[i2-2])*grid0[0,i]
grid2[-1,2*i] = grid0[-1,i]
grid2[-1,2*i-1] = hx2[i2-1]/(hx2[i2-1]+hx2[i2-2])*grid0[-1,i-1]+hx2[i2-2]/(hx2[i2-1]+hx2[i2-2])*grid0[-1,i]
grid2[0,int(hx0.size*2)] = grid0[0,hx0.size] #邊界最後一個點
grid2[-1,int(hx0.size*2)] = grid0[-1,hx0.size] #邊界最後一個點
for j in range(1, hy0.size+1):#賦值邊界
j2 = j*2
grid2[2*j,0] = grid0[j,0]
grid2[2*j-1,0] = hy2[j2-1]/(hy2[j2-1]+hy2[j2-2])*grid0[j-1,0]+hy2[j2-2]/(hy2[j2-1]+hy2[j2-2])*grid0[j,0]
grid2[2*j,-1] = grid0[j,-1]
grid2[2*j-1,-1] = hy2[j2-1]/(hy2[j2-1]+hy2[j2-2])*grid0[j-1,-1]+hy2[j2-2]/(hy2[j2-1]+hy2[j2-2])*grid0[j,-1]
grid2[int(hy0.size*2),0] = grid0[hy0.size,0] #邊界最後一個點
grid2[int(hy0.size*2),-1] = grid0[hy0.size,-1] #邊界最後一個點
return grid2
def hx_level(xsize):
level = int(math.log2((nx_grid-1)/xsize))# 計算粗化了幾次
dstep = int(2**(level))
hx2_grid = int((hx.size)/dstep)
hy2_grid = int((hy.size)/dstep)
hx2 = np.zeros(hx2_grid, dtype = float)
hy2 = np.zeros(hy2_grid, dtype = float)
for i in range(0, hx2.size):
j0 = dstep*i
h2_step = 0.
for j in range(dstep):
h2_step = h2_step + hx[j0 + j]
hx2[i] = h2_step
for i in range(0, hy2.size):
j0 = dstep*i
h2_step = 0.
for j in range(dstep):
h2_step = h2_step + hy[j0 + j]
hy2[i] = h2_step
x2 = np.zeros((hx2.size+1), dtype = float)
y2 = np.zeros((hy2.size+1), dtype = float)
x2[0] = xs
y2[0] = ys
for i in range(1, x2.size):# 賦值x2,默認不等距網格
x2[i] = x2[i-1]+hx2[i-1]
for j in range(1, y2.size):# 賦值y2,默認不等距網格
y2[j] = y2[j-1]+hy2[j-1]
return hx2,hy2,x2,y2
def coarsen2(grid0,hx0,hy0):
#dstep = int(2**(level-1))
nx_grid2 = int((hx0.size)/2 + 1) #x 方向粗化後網格數量
ny_grid2 = int((hy0.size)/2 + 1)
grid2 = np.zeros((ny_grid2,nx_grid2), dtype = float)
hx2 = np.zeros((nx_grid2-1), dtype = float)
hy2 = np.zeros((ny_grid2-1), dtype = float)
x2 = np.zeros((nx_grid2), dtype = float)
y2 = np.zeros((ny_grid2), dtype = float)
x2[0] = xs
y2[0] = ys
for i in range(1, nx_grid2-1):
for j in range(1, ny_grid2-1): #賦值中間的網格
i2 = 2*i
j2 = 2*j
weight_total = 1./hx0[i2-1]+1./hx0[i2]+1./hy0[j2-1]+1./hy0[j2]
weight1 = (1./hx0[i2-1])/weight_total # 周邊四個網格的權重
weight2 = (1./hx0[i2])/weight_total
weight3 = (1./hy0[j2-1])/weight_total
weight4 = (1./hy0[j2])/weight_total
grid2[j,i] = 0.4*grid0[j2,i2] + 0.6*weight1*grid0[j2,i2-1] + 0.6*weight2*grid0[j2,i2+1]+0.6*weight3*grid0[j2-1,i2]+0.6*weight4*grid0[j2+1,i2]
for j in range(0, ny_grid2):#賦值邊界
grid2[j,0] = grid0[2*j,0]
grid2[j,-1] = grid0[2*j,-1]
for i in range(0, nx_grid2):
grid2[0,i] = grid0[0,2*i]
grid2[-1,i] = grid0[-1,2*i]
return grid2#,hx2,hy2,x2,y2
def Relax2(b2, phi0, hx0,hy0,x1,x2):#
omig = 1.85 #鬆弛迭代法
leveli = int(round(math.log2((nx_grid-1)/hx0.size)))# 四捨五入後不容易出錯
print('level',leveli)
ite = 2*((leveli)*leveli*leveli*leveli)
k = -2 #k 取負)值可保證至少迭代一定次數
while(k <ite):
print(k)
for j in range(0,hy0.size+1): #向上
for i in range(1,hx0.size): #沿着橫座標。 非均勻網格要改這裏
if j == 0: #最低下一行
phi0[j,i] = np.copy(phi0[j+1,i])
elif j == hy0.size:
phi0[j,i] = np.copy(phi0[j-1,i])#最上一行
else:#五點差分法
#phi0[j,i] = (1-omig)*np.copy(phi0[j,i])+omig*(np.copy(phi0[j,i-1])+np.copy(phi0[j,i+1])+np.copy(phi0[j-1,i])+np.copy(phi0[j+1,i])+h[i]*h[i]* b2[i,j])/4.
cofficient1 = 2./(hx0[i]+hx0[i-1])
cofficient2 = 2./(hy0[j]+hy0[j-1])
cofficient_u = cofficient1/hx0[i]+cofficient1/hx0[i-1]+cofficient2/hy0[j]+cofficient2/hy0[j-1]
point_l = cofficient1*np.copy(phi0[j,i-1])/hx0[i-1]
point_r = cofficient1*np.copy(phi0[j,i+1])/hx0[i]
point_u = cofficient2*np.copy(phi0[j+1,i])/hy0[j]
point_d = cofficient2*np.copy(phi0[j-1,i])/hy0[j-1]
phi0[j,i] = (1-omig)*np.copy(phi0[j,i])+omig*(point_l+point_r+point_u+point_d+ b2[j,i])/cofficient_u
k = k+1
return phi0
def b2hxy(x1,x2):
b2 = np.zeros((x2.size,x1.size), dtype = float)
for j in range(0, x2.size):# y
for i in range(0,x1.size):#x
b2[j,i] = bxy(x2[j],x1[i])
return b2
def residual(br, v, h,x1,x2): #計算殘差, 後來感覺這步多餘就刪掉了
r = np.zeros((h.size+1,h.size+1), dtype = float)
for j in range(1,h.size): #向上
for i in range(1,h.size): #沿着橫座標
r[j,i] = br[i,j]-(4.*np.copy(v[j,i])-np.copy(v[j,i-1])-np.copy(v[j,i+1])-np.copy(v[j-1,i])-np.copy(v[j+1,i]))/h[i]/h[i]
return r
def MG(b_mg,phi0, x121, y121, hx0,hy0,level_total):
vh = Relax2(b_mg,phi0, hx0,hy0, x121, y121)
hx2,hy2,x12,x22 = hx_level(int(vh.shape[1]-1))
for i in range (1, level_total): #coarse and iterate
print(i)
v2h0 = coarsen2(vh,hx2,hy2)
b2h0 = coarsen2(b_mg,hx2,hy2)
hx2,hy2,x12,x22 = hx_level(int(v2h0.shape[1]-1))
v2h = Relax2(b2h0,v2h0, hx2,hy2, x12, x22)
vh = v2h
b_mg = b2h0
for i in range (1, level_total): # fine and itearate
print(i)
v2h0 = fine2(vh,hx2,hy2)
b2h0 = fine2(b_mg,hx2,hy2)
hx2,hy2,x12,x22 = hx_level(int(v2h0.shape[1]-1))
v2h = Relax2(b2h0,v2h0, hx2,hy2, x12, x22)
vh = v2h
b_mg = b2h0
return vh,x12,x22
def init(nx_grid,ny_grid,xs,xe,ys,ye,xleft_boundary_value,xright_boundary_value,dyleft_boundary_value,dyright_boundary_value):
hx = (xe-xs)/(nx_grid-1)* np.ones(nx_grid-1, dtype = float) #x 方向步長,可以是非等距
hy = (ye-ys)/(ny_grid-1)* np.ones(ny_grid-1, dtype = float) #y 方向步長
x = np.zeros(nx_grid, dtype = float)
x[0] = xs
x[-1] = xe
for i in range(1, nx_grid-1):
x[i] = x[i-1] + hx[i-1]
y = np.zeros(ny_grid, dtype = float)
y[0] = ys
y[-1] = ye
for i in range(1, ny_grid-1): # initialize x and y
y[i] = y[i-1] + hy[i-1]
phi = np.ones((y.size,x.size), dtype = float)*0.1 # initialize results
phi[:,0] = xleft_boundary_value
phi[:,-1] = xright_boundary_value
b = np.zeros((y.size,x.size), dtype = float)# initialize b
for i in range(0, nx_grid):
for j in range(0, ny_grid):
b[j,i] = bxy(x[i],y[j])
return x,y,hx,hy,phi,b
def bxy(x0,y0):#方程右邊的函數
return -2.*math.pi*math.pi*math.sin(math.pi*x0)*math.cos(math.pi*y0)
nx_grid = 513 #at least 512 grids to reach enough depth
xs = -1.
xe = 1.
ny_grid = 65 #at least 512 grids to reach enough depth
ys = -1.
ye = 1.
level_total = 4# 4重網格
xleft_boundary_value = 0. # u(x = -1) = u(x = 1) = 0
xright_boundary_value = 0.
dyleft_boundary_value = 0. # du(y = -1) = u(y = 1) = 0
dyright_boundary_value = 0.
x,y,hx,hy,phi,b = init(nx_grid,ny_grid,xs,xe,ys,ye,xleft_boundary_value,xright_boundary_value,dyleft_boundary_value,dyright_boundary_value)
grid2 = coarsen2(b,hx,hy)
hx2,hy2,x2,y2 = hx_level(grid2.shape[1]-1)
grid3 = fine2(grid2,hx2,hy2)
hx3,hy3,x3,y3 = hx_level(grid3.shape[1]-1)
#print('hx',hx)
#hxlevel2,hylevel2,x22,y22 = hx_level(hx2.size)
#phi2 = Relax2(b,phi, hx,x,y)
result,x121,y121 = MG(b,phi, x, y, hx,hy,level_total)
#result = Relax2(b, phi, hx,hy,x,y)
#hxr,hyr,xr,yr = hx_level(result.shape[1])
print(result.max(),result.min())
X,Y = np.meshgrid(x121,y121)
fig1 = plt.figure(1)
ax = fig1.gca(projection = '3d')
#contourf(x121,y121, result, 80, cmap = 'seismic')
ax.plot_surface(X,Y, result,cmap = plt.get_cmap('jet'))
#plt.colorbar()
plt.figure(2)
contourf(x, y, b, 80, cmap = 'seismic')
plt.colorbar()
plt.show()
plt.close()
結果如下
```