二维扩散方程,使用差分法应用诺伊曼条件

时间:2018-06-27 14:41:14

标签: python differential-equations

我正在尝试对以温度T(x,y)开始的矩形薄片建模,我想看看它是如何随时间变化的。 我尝试修改此程序: https://github.com/hplgit/fdm-book/blob/master/src/diffu/diffu2D_u0.py resolver_sparse函数,但是我希望图纸的边界是绝热的,如何将Neumann条件应用于此呢?即dT / dx = 0(跨边界)。

编辑: 我知道我可以使用U_0x等将边界温度设置为特定值,但是我认为这只是强制将温度指定为该值,而不是强制将热交换设置为0。温度30K,然后将下y边界强制为15K,将上y边界强制为45K,如何为所有边界指定绝热壁?结果应该是沿x轴温度从15K升高到45K的条纹。     将numpy导入为np     导入scipy.sparse     导入scipy.sparse.linalg     从matplotlib导入pyplot作为plt

def solver_sparse(
    I, a, f, Lx, Ly, Nx, Ny, dt, T, theta=0.5,
    U_0x=0, U_0y=0, U_Lx=0, U_Ly=0, user_action=None,
    method='direct', CG_prec='ILU', CG_tol=1E-5):
    """
    Full solver for the model problem using the theta-rule
    difference approximation in time. Sparse matrix with
    dedicated Gaussian elimination algorithm (method='direct')
    or ILU preconditioned Conjugate Gradients (method='CG' with
    tolerance CG_tol and preconditioner CG_prec ('ILU' or None)).
    """
    import time; t0 = time.clock()  # for measuring CPU time

    x = np.linspace(0, Lx, Nx+1)       # mesh points in x dir
    y = np.linspace(0, Ly, Ny+1)       # mesh points in y dir
    dx = x[1] - x[0]
    dy = y[1] - y[0]

    dt = float(dt)                  # avoid integer division
    Nt = int(round(T/float(dt)))
    t = np.linspace(0, Nt*dt, Nt+1) # mesh points in time

    # Mesh Fourier numbers in each direction
    Fx = a*dt/dx**2
    Fy = a*dt/dy**2

    # Allow f to be None or 0
    if f is None or f == 0:
        f = lambda x, y, t: np.zeros((x.size, y.size)) \
            if isinstance(x, np.ndarray) else 0

    u   = np.zeros((Nx+1, Ny+1))    # unknown u at new time level
    u_n = np.zeros((Nx+1, Ny+1))    # u at the previous time level

    Ix = range(0, Nx+1)
    Iy = range(0, Ny+1)
    It = range(0, Nt+1)

    # Make U_0x, U_0y, U_Lx and U_Ly functions if they are float/int
    if isinstance(U_0x, (float,int)):
        _U_0x = float(U_0x)  # Make copy of U_0x
        U_0x = lambda t: _U_0x
    if isinstance(U_0y, (float,int)):
        _U_0y = float(U_0y)  # Make copy of U_0y
        U_0y = lambda t: _U_0y
    if isinstance(U_Lx, (float,int)):
        _U_Lx = float(U_Lx)  # Make copy of U_Lx
        U_Lx = lambda t: _U_Lx
    if isinstance(U_Ly, (float,int)):
        _U_Ly = float(U_Ly)  # Make copy of U_Ly
        U_Ly = lambda t: _U_Ly

    # Load initial condition into u_n
    for i in Ix:
        for j in Iy:
            u_n[i,j] = I(x[i], y[j])

    # Two-dim coordinate arrays for vectorized function evaluations
    xv = x[:,np.newaxis]
    yv = y[np.newaxis,:]

    if user_action is not None:
        user_action(u_n, x, xv, y, yv, t, 0)

    N = (Nx+1)*(Ny+1)
    main   = np.zeros(N)            # diagonal
    lower  = np.zeros(N-1)          # subdiagonal
    upper  = np.zeros(N-1)          # superdiagonal
    lower2 = np.zeros(N-(Nx+1))     # lower diagonal
    upper2 = np.zeros(N-(Nx+1))     # upper diagonal
    b      = np.zeros(N)            # right-hand side



    # Precompute sparse matrix
    lower_offset = 1
    lower2_offset = Nx+1

    m = lambda i, j: j*(Nx+1) + i
    j = 0; main[m(0,j):m(Nx+1,j)] = 1  # j=0 boundary line
    for j in Iy[1:-1]:             # Interior mesh lines j=1,...,Ny-1
        i = 0;   main[m(i,j)] = 1  # Boundary
        i = Nx;  main[m(i,j)] = 1  # Boundary
        # Interior i points: i=1,...,N_x-1
        lower2[m(1,j)-lower2_offset:m(Nx,j)-lower2_offset] = - theta*Fy
        lower[m(1,j)-lower_offset:m(Nx,j)-lower_offset] = - theta*Fx
        main[m(1,j):m(Nx,j)] = 1 + 2*theta*(Fx+Fy)
        upper[m(1,j):m(Nx,j)] = - theta*Fx
        upper2[m(1,j):m(Nx,j)] = - theta*Fy
    j = Ny; main[m(0,j):m(Nx+1,j)] = 1  # Boundary line

    A = scipy.sparse.diags(
        diagonals=[main, lower, upper, lower2, upper2],
        offsets=[0, -lower_offset, lower_offset,
                 -lower2_offset, lower2_offset],
        shape=(N, N), format='csc')
    print(A.todense())   # Check that A is correct

    if method == 'CG':
        if CG_prec == 'ILU':
            # Find ILU preconditioner (constant in time)
            A_ilu = scipy.sparse.linalg.spilu(A)  # SuperLU defaults
            M = scipy.sparse.linalg.LinearOperator(
                shape=(N, N), matvec=A_ilu.solve)
        else:
            M = None
        CG_iter = []  # No of CG iterations at time level n

    # Time loop
    for n in It[0:-1]:
        """
        # Compute b, scalar version
        j = 0
        for i in Ix:
            p = m(i,j);  b[p] = U_0y(t[n+1])          # Boundary
        for j in Iy[1:-1]:
            i = 0;  p = m(i,j);  b[p] = U_0x(t[n+1])  # Boundary
            for i in Ix[1:-1]:
                p = m(i,j)                            # Interior
                b[p] = u_n[i,j] + \
                  (1-theta)*(
                  Fx*(u_n[i+1,j] - 2*u_n[i,j] + u_n[i-1,j]) +\
                  Fy*(u_n[i,j+1] - 2*u_n[i,j] + u_n[i,j-1]))\
                    + theta*dt*f(i*dx,j*dy,(n+1)*dt) + \
                  (1-theta)*dt*f(i*dx,j*dy,n*dt)
            i = Nx;  p = m(i,j);  b[p] = U_Lx(t[n+1]) # Boundary
        j = Ny
        for i in Ix:
            p = m(i,j);  b[p] = U_Ly(t[n+1])          # Boundary
        #print b
        """
        # Compute b, vectorized version

        # Precompute f in array so we can make slices
        f_a_np1 = f(xv, yv, t[n+1])
        f_a_n   = f(xv, yv, t[n])

        u_n[:, 0] = u_n[:, 1]
        u_n[:, Ny] = u_n[:, Ny - 1]

        j = 0; b[m(0,j):m(Nx+1,j)] =u_n[0:Nx+1,j] #U_0y(t[n+1])     # Boundary
        j = Ny;b[m(0, j):m(Nx + 1, j)] = u_n[0:Nx+1,j] #U_Ly(t[n+1]) # Boundary

        u_n[0, :] = u_n[1, :]
        u_n[Nx, :] = u_n[Nx - 1, :]


        for j in Iy[1:-1]:
            # i = 0;   p = m(i,j);  b[p] = U_0x(t[n+1]) # Boundary
            # i = Nx;  p = m(i,j);  b[p] = U_Lx(t[n+1]) # Boundary


            i = 0;   p = m(i,j);  b[p] = u_n[i,j]
            i = Nx;  p = m(i,j);  b[p] = u_n[i,j] # Boundary



            imin = Ix[1]

            imax = Ix[-1]  # for slice, max i index is Ix[-1]-1

            # b[m(imin,j):m(imax,j)] = u_n[imin:imax,j] + (1-theta)*(Fx*(u_n[imin+1:imax+1,j] - 2*u_n[imin:imax,j] +u_n[imin-1:imax-1,j]) +Fy*(u_n[imin:imax,j+1] -
            #    2*u_n[imin:imax,j] + u_n[imin:imax,j-1])) + theta*dt*f_a_np1[imin:imax,j] + (1-theta)*dt*f_a_n[imin:imax,j]
            b[m(imin,j):m(imax,j)] = u_n[imin:imax,j] + (1-theta)*(Fx*(u_n[imin+1:imax+1,j] - 2*u_n[imin:imax,j] +u_n[imin-1:imax-1,j]) +Fy*(u_n[imin:imax,j+1] -
                           2*u_n[imin:imax,j] + u_n[imin:imax,j-1])) + theta*dt*f_a_np1[imin:imax,j] + (1-theta)*dt*f_a_n[imin:imax,j]


        b[0]=4.2
        b[-1]=100

        # Solve matrix system A*c = b
        if method == 'direct':
            c = scipy.sparse.linalg.spsolve(A, b)
        elif method == 'CG':
            x0 = u_n.T.reshape(N)  # Start vector is u_n
            CG_iter.append(0)

            def CG_callback(c_k):
                """Trick to count the no of iterations in CG."""
                CG_iter[-1] += 1

            c, info = scipy.sparse.linalg.cg(
                A, b, x0=x0, tol=CG_tol, maxiter=N, M=M,
                callback=CG_callback)
            '''
            if info > 0:
                print 'CG: tolerance %g not achieved within %d iterations' \
                      % (CG_tol, info)
            elif info < 0:
                print 'CG breakdown'
            else:
                print 'CG converged in %d iterations (tol=%g)' \
                      % (CG_iter[-1], CG_tol)
            '''
        # Fill u with vector c
        #for j in Iy:  # vectorize y lines
        #    u[0:Nx+1,j] = c[m(0,j):m(Nx+1,j)]
        u[:,:] = c.reshape(Ny+1,Nx+1).T


        if user_action is not None:
            user_action(u, x, xv, y, yv, t, n+1)

        # Update u_n before next step
        u_n, u = u, u_n

    # Plot the graph
    fig, ax = plt.subplots()
    cax = ax.contourf(x, y, u, 50, cmap='jet')
    cbar = fig.colorbar(cax)
    ax.set_xlabel('Axial position from centre (m)')
    ax.set_ylabel(r'$ \phi $ (°)')

    t1 = time.clock()

    return t, t1-t0

def I(x, y):
    return 4.2

solver_sparse(I,2,0,20,20,20,20,5,800)
plt.show()

我相信这些使边界绝热,并且它适用于2D图纸,其中一侧为10K,另一侧为4.2K,而另外两壁为绝热。产生条纹图。但是,如果我将所有墙壁都绝热并且将温度降低的所有地方的初始温度场设置为4.2K,即加热消失了。 u_n [0,:] = u_n [1,:] u_n [Nx,:] = u_n [Nx-1,:] 谢谢您的帮助

0 个答案:

没有答案