我正在尝试对以温度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,:] 谢谢您的帮助