多重網格法-鬆弛迭代法-二維泊松方程-python實現(非等距網格情形)

上一篇文章寫了正方形網格的情形,實際計算中常常用到非等距矩形網格,因此我把上個代碼改成了非等距形式。改成非等距形式後,五點差分法將泊松方程化成方程組時,公式形式和正方形形式稍微不一樣,我推了一下,沒查任何文獻,不保證正確。方程左邊是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()

結果如下

``在這裏插入圖片描述`

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章