【问题标题】:Finite difference method for 3D diffusion/heat equation3D 扩散/热方程的有限差分法
【发布时间】:2020-11-10 05:24:29
【问题描述】:

我正在尝试使用有限差分来求解 3D 中的扩散方程。我想我的主循环有问题。特别是离散方程为:

用诺依曼边界条件(仅以一个面为例):

现在是代码:

import numpy as np
from matplotlib import pyplot, cm
from mpl_toolkits.mplot3d import Axes3D ##library for 3d projection plots
%matplotlib inline

kx = 15     #Number of points
ky = 15
kz = 15
largx = 90  #Domain length.
largy = 90
largz = 90   

dt4 = 1/2 #Time delta (arbitrary for the time).
dx4 = largx/(kx-1)    #Position deltas.
dy4 = largy/(ky-1)
dz4 = largz/(kz-1) 

Tin = 25    #Initial temperature
kapp = 0.23

Tamb3d = 150 #Ambient temperature

#Heat per unit of area. One for each face.
qq1=0 / (largx*largz)
qq2=0 / (largx*largz)
qq3=0 / (largz*largy)
qq4=0 / (largz*largy)
qq5=0 / (largx*largy)
qq6=1000 / (largx*largy)


x4 = np.linspace(0,largx,kx)   
y4 = np.linspace(0,largy,ky)
z4 = np.linspace(0,largz,kz)


#Defining the function.
def diff3d(tt):
    
    w2 = np.ones((kx,ky,kz))*Tin         #Temperature array
    wn2 = np.ones((kx,ky,kz))*Tin
    
    for k in range(tt+2):
        wn2 = w2.copy()
        w2[1:-1,1:-1,1:-1] = (wn2[1:-1,1:-1,1:-1] + 
                        kapp*dt4 / dy4**2 *                                       
                        (wn2[1:-1, 2:,1:-1] - 2 * wn2[1:-1, 1:-1,1:-1] + wn2[1:-1, 0:-2,1:-1]) +  
                        kapp*dt4 / dz4**2 *                                       
                        (wn2[1:-1,1:-1,2:] - 2 * wn2[1:-1, 1:-1,1:-1] + wn2[1:-1, 1:-1,0:-2]) +
                        kapp*dt4 / dx4**2 *
                        (wn2[2:,1:-1,1:-1] - 2 * wn2[1:-1, 1:-1,1:-1] + wn2[0:-2, 1:-1,1:-1]))

        #Neumann boundary (dx=dy=dz for the time)
        w2[0,:,:] =   w2[0,:,:] + 2*kapp* (dt4/(dx4**2)) * (w2[1,:,:] - w2[0,:,:] - qq1 * dx4/kapp)
        w2[-1,:,:] =  w2[-1,:,:] + 2* kapp*(dt4/(dx4**2)) * (w2[-2,:,:] - w2[-1,:,:] + qq2 * dx4/kapp)
        w2[:,0,:] =   w2[:,0,:] + 2*kapp* (dt4/(dx4**2)) * (w2[:,1,:] - w2[:,0,:] - qq3 * dx4/kapp)
        w2[:,-1,:] =  w2[:,-1,:] + 2*kapp* (dt4/(dx4**2)) * (w2[:,-2,:] - w2[:,-1,:] + qq4 * dx4/kapp)
        w2[:,:,0] =   w2[:,:,0] + 2 *kapp* (dt4/(dx4**2)) * (w2[:,:,-1] - w2[:,:,0] - qq5 * dx4/kapp)
        w2[:,:,-1] =   w2[:,:,-1] + 2 *kapp* (dt4/(dx4**2)) * (w2[:,:,-2] - w2[:,:,-1] + qq6 * dx4/kapp)
       
    w2[1:,:-1,:-1] = np.nan    #We'll only plot the "outside" points.
    w2_uno = np.reshape(w2,-1)    

    #Plotting
    fig = pyplot.figure()
    X4, Y4, Z4 = np.meshgrid(x4, y4,z4)
    ax = fig.add_subplot(111, projection='3d')
    img = ax.scatter(X4, Y4, Z4, c=w2_uno, cmap=pyplot.jet())
    fig.colorbar(img)
    pyplot.show()

对于 5000 次迭代 (qq6 = 1000/Area),我们得到:

我只在顶部表面加热。不知何故,我最终导致底部表面升温。

除此之外,我还试图限制我施加热量的区域(只是一张脸的一小部分)。当我尝试时,似乎热量只向一个方向传递,而忽略了所有其他方向。将 (qq1 = 1000/Area) 应用于一半的正面(另一部分是绝热的,q = 0)我们最终得到:

这很奇怪。我怀疑我在主循环(或者边界条件)中遇到了一些我没有找到的问题。

【问题讨论】:

    标签: python numpy physics pde heat


    【解决方案1】:

    也许您可以尝试更多测试驱动的方法。一个帮助是 Python slice 命令。它在 numpy 数组访问中速度很快,并且在有限差分中的使用更不容易出错。试试看:

    import numpy as np
    
    def get_slices(mx, my, mz):
        jxw, jxp, jxe = slice(0,mx-2), slice(1,mx-1), slice(2,mx)  # west,  center, east
        jys, jyp, jyn = slice(0,my-2), slice(1,my-1), slice(2,my)  # south, center, north
        jzb, jzp, jzt = slice(0,mz-2), slice(1,mz-1), slice(2,mz)  # botoom,center, top
        return jxw, jxp, jxe,   jys, jyp, jyn,    jzb, jzp, jzt
    
    nx, ny, nz = 15, 10, 15
    jxw, jxp, jxe, \
    jys, jyp, jyn, \
    jzb, jzpc, jzt = get_slices(nx, ny, nz)
    
    ax, ay, az = np.arange(nx), np.arange(ny), np.arange(nz)
    
    print('axW', ax[jxw])
    print('axP', ax[jxp])
    print('axE', ax[jxe])
    
    axW [ 0  1  2  3  4  5  6  7  8  9 10 11 12]
    axP [ 1  2  3  4  5  6  7  8  9 10 11 12 13]
    axE [ 2  3  4  5  6  7  8  9 10 11 12 13 14]
    

    我不太确定您的代码中的图形向我们展示了什么。因此,通过对 T(或 w2)使用不同的初始化以及不完全相同的 kx, ky, kz 值仔细检查它。注意np.meshgrid() 命令中的indexing="ij" 选项。使用np.nan 有点危险,因为它会全局更改变量。

    import numpy as np
    from matplotlib import pyplot as plt
    from matplotlib import cm
    from mpl_toolkits.mplot3d import Axes3D
    
    def get_grid(mx, my, mz, Lx,Ly,Lz):
        ix, iy, iz = Lx*np.linspace(0,1,mx), Ly*np.linspace(0,1,my), Lz*np.linspace(0,1,mz)
        x, y, z = np.meshgrid(ix,iy,iz, indexing='ij')
        print('ix', ix), print('iy', iy), print('iz', iz)
        return x,y,z
    
    def plot_grid(x,y,z,T):
        def plot_boundary_only(x,y,z,T):
            mx, my, mz = x.shape
            x[1:-1, 1:-1, 1:-1],y[1:-1, 1:-1, 1:-1],z[1:-1, 1:-1, 1:-1],T[1:-1, 1:-1, 1:-1] = np.nan, np.nan, np.nan, np.nan     # remove interior
            x[1:-1, 1:,0], y[1:-1, 1:,0], z[1:-1, 1:,0],  T[1:-1, 1:,0] = np.nan, np.nan, np.nan, np.nan                         # remove bottom
            x[1:-1, my-1, 1:-1], y[1:-1, my-1, 1:-1], z[1:-1, my-1, 1:-1], T[1:-1, my-1, 1:-1] = np.nan, np.nan, np.nan, np.nan  # remove north face
            x[0, 1:, :-1], y[0, 1:, :-1], z[0, 1:, :-1], T[0, 1:, :-1] = np.nan, np.nan, np.nan, np.nan                          # remove west face
            return x,y,z,T
        
        x,y,z,T = plot_boundary_only(x,y,z,T)   
        fig = plt.figure(figsize=(15,15))
        ax = fig.add_subplot(111, projection='3d')
        img = ax.scatter(x,y,z, c=T.reshape(-1), s=150, cmap=plt.jet())
        fig.colorbar(img)
        
        #ax.zaxis.set_rotate_label(False) # To disable automatic label rotation
        ax.set_ylabel('Y')
        ax.set_xlabel('X', rotation=0)
        ax.set_zlabel('Z', rotation=0)
        plt.savefig("cube.png")
        plt.show()
        
    def init_T(x,y,z):
        T = np.zeros_like(x)
        case = 'xz'
        if case == 'x': T = x
        if case == 'y': T = y
        if case == 'z': T = z
        if case == 'xz': T = x+z
        return T
    
    nx, ny, nz = 35, 20, 30
    Lx, Ly, Lz = nx-1, ny-1, nz-1
    x,y,z = get_grid(nx, ny, nz, Lx,Ly,Lz)  # generate a grid with mesh size Δx = Δy = Δz = 1
    T = init_T(x,y,z)
    plot_grid(x,y,z,T)
    

    这是运行热方程求解器的主程序。请注意,我们不能使用显示表面点的图形来查看任何结果! Neumann 条件在我们看不到的底部,而面的值是固定值边界条件,不会改变。

    def set_GradBC(u):
        #--- Neuman BC at bottom boundary ---
        u[:, :, 0] = u[:, :, 1]
        return u
    
    
    def dT(u,DU):
        DU[jxp,jyp,jzp] = (u[jxe,jyp,jzp] - 2.0*u[jxp,jyp,jzp] + u[jxw,jyp,jzp])*Dx + \
                          (u[jxp,jyn,jzp] - 2.0*u[jxp,jyp,jzp] + u[jxp,jys,jzp])*Dy + \
                          (u[jxp,jyp,jzt] - 2.0*u[jxp,jyp,jzp] + u[jxp,jyp,jzb])*Dz
        return DU
    
    #mmmmmmmmmmmmm main mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
    #---- set the parameters ------------------------
    dt = 0.01                                    # time step size
    nIterations = 5000                           # number of iterations
    nx, ny, nz = 40,20,30                       # number of grid points
    Lx, Ly, Lz = nx-1, ny-1, nz-1                 # physical grid size
    Kx, Ky, Kz = 1, 1, 1                          # diffusion coeficients
    dx, dy, dz = Lx/(nx-1), Ly/(ny-1), Lz/(nz-1)  # mesh size
    Dx, Dy, Dz = Kx/dx**2, Ky/dy**2, Kz/dz**2     # equation coefficients
    
    #---- initialize the field variables -----------------
    x,y,z = get_grid(nx, ny, nz, Lx,Ly,Lz)       # generate the grid
    T = init_T(x,y,z)                            # initialize the temperature
    DT = np.zeros_like(T)                        # initialize the change of temperature
    jxw, jxp, jxe, \
    jys, jyp, jyn, \
    jzb, jzp, jzt = get_slices(nx, ny, nz)       # slices for finite differencing
    
    #---- run the solving algorithm ----------------------
    for jter in range(nIterations):
        T = set_GradBC(T)              # set Neumann boundary condition
        T = T + dt*dT(T,DT)            # update
    

    这是沿 JY1=constant 显示结果的切片

    def plot_y_slice(JY1, x,y,z,T):
        T2 = T[:,JY1,:]
        X =  x[:,JY1,:]
        Z =  z[:,JY1,:]
    
        fig = plt.figure(figsize=(15,15))
        ax = fig.add_subplot(111)
        ax.set_aspect('equal')
        plt.contourf(X,Z,T2, 40,alpha=0.99)
        plt.savefig("y_slice.png")
        plt.show()
        
    JY1 = 10
    plot_y_slice(JY1, x,y,z,T)
    

    【讨论】:

      【解决方案2】:

      这段代码有问题: w2[:,:,0] = w2[:,:,0] + 2 kapp (dt4/(dx4**2)) * (w2[:,:,-1] - w2 [:,:,0] - qq5 * dx4/kapp) 请再次检查。 我最近正在做一个类似的项目。有没有时间和我分享一下经验。

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-12
      • 1970-01-01
      相关资源
      最近更新 更多