上一篇文章写了正方形网格的情形,实际计算中常常用到非等距矩形网格,因此我把上个代码改成了非等距形式。改成非等距形式后,五点差分法将泊松方程化成方程组时,公式形式和正方形形式稍微不一样,我推了一下,没查任何文献,不保证正确。方程左边是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()
结果如下
```