我正在寻找一种用python解决二维热方程的方法。我已经实现了有限差分方法但是慢动作(使100,000次模拟需要30分钟)。我们的想法是创建一个端点可以编写的代码,
for t in TIME:
DeltaU=f(U)
U=U+DeltaU*DeltaT
save(U)
我该怎么做?
在我的代码的第一种形式中,我使用了有限差分的2D方法,我的格栅是5000x250(x,y)。现在我想降低计算速度,想法是找到
DeltaU = f(u)
其中U是加热功能。为了实现,我将此源http://www.timteatro.net/2010/10/29/performance-python-solving-the-2d-diffusion-equation-with-numpy/用于2D情况,但运行时间对于我的必要性来说更昂贵。有没有一些方法可以做到这一点?
也许我必须使用矩阵
A=1/dx^2 (2 -1 0 0 ... 0
-1 2 -1 0 ... 0
0 -1 2 -1 ... 0
. .
. .
. .
0 ... -1 2)
但是如何在2D问题中做到这一点?如何在A中插入边界条件? 这是我使用的有限差分的代码:
Lx=5000 # physical length x vector in micron
Ly=250 # physical length y vector in micron
Nx = 100 # number of point of mesh along x direction
Ny = 50 # number of point of mesh along y direction
a = 0.001 # diffusion coefficent
dx = 1/Nx
dy = 1/Ny
dt = (dx**2*dy**2)/(2*a*(dx**2 + dy**2)) # it is 0.04
x = linspace(0.1,Lx, Nx)[np.newaxis] # vector to create mesh
y = linspace(0.1,Ly, Ny)[np.newaxis] # vector to create mesh
I=sqrt(x*y.T) #initial data for heat equation
u=np.ones(([Nx,Ny])) # u is the matrix referred to heat function
steps=100000
for m in range (0,steps):
du=np.zeros(([Nx,Ny]))
for i in range (1,Nx-1):
for j in range(1,Ny-1):
dux = ( u[i+1,j] - 2*u[i,j] + u[i-1, j] ) / dx**2
duy = ( u[i,j+1] - 2*u[i,j] + u[i, j-1] ) / dy**2
du[i,j] = dt*a*(dux+duy)
# Boundary Conditions
t1=(u[:,0]+u[:,1])/2
u[:,0]=t1
u[:,1]=t1
t2=(u[0,:]+u[1,:])/2
u[0,:]=t2
u[1,:]=t2
t3=(u[-1,:]+u[-2,:])/2
u[-1,:]=t3
u[-2,:]=t3
u[:,-1]=1
filename1='data_{:08d}.txt'
if m%100==0:
np.savetxt(filename1.format(m),u,delimiter='\t' )
对于精心制作的100000步骤,运行时间约为30分钟。我想优化这段代码(初始行中提出的想法),运行时间约为5/10分钟或者减去。我该怎么办?
答案 0 :(得分:1)
您是否考虑过对代码进行并行化或使用GPU加速。
如果你运行代码python profiler(cProfile)会有所帮助,这样你就可以弄清楚运行时瓶颈在哪里。我假设它是在解决你得到的矩阵方程式,可以通过我上面列出的方法轻松加速。
答案 1 :(得分:0)
我可能错了,但在你为时间步骤创建的循环代码中," m在范围(步骤)" 在下面的一行中,您继续; Du = np.zeros(----)。 不是python的专家,但这可能导致在步数中创建稀疏矩阵,在这种情况下为100k次。
答案 2 :(得分:0)
有一些简单但巨大的改进可能:
仅仅通过引入 'Dxx, Dyy = 1/(dxdx), 1/(dydy)' 运行时间下降了 25%。通过使用切片并避免 for 循环,代码现在快了 400 倍
def f_for(u):
for m in range (0,steps):
du=np.zeros((Nx,Ny))
for i in range (1,Nx-1):
for j in range(1,Ny-1):
dux = ( u[i+1,j] - 2*u[i,j] + u[i-1, j] ) / dx**2
duy = ( u[i,j+1] - 2*u[i,j] + u[i, j-1] ) / dy**2
du[i,j] = dt*a*(dux+duy)
def f_slice(u):
Dxx, Dyy = 1/dx**2, 1/dy**2
i = slice(1,nx-1); iw = slice(0,nx-2); ie = slice(2,nx)
j = slice(1,ny-1); js = slice(0,ny-2); jn = slice(2,ny)
for m in range (0,steps):
dux = Dxx* ( u[ie,j] - 2*u[i,j] + u[iw, j] )
duy = Dyy* ( u[i,jn] - 2*u[i,j] + u[i, js] )
du[i,j] = dt*a*(dux+duy)
Nx = 100 # number of point of mesh along x direction
Ny = 50 # number of point of mesh along y direction
a = 0.001 # diffusion coefficent
dx = 1/Nx
dy = 1/Ny
dt = (dx**2*dy**2)/(2*a*(dx**2 + dy**2))
steps=100000
steps=100
U=np.ones(([Nx,Ny])) # u is the matrix referred to heat function
%timeit f_for(U)
%timeit f_slice(U)