如何使我的 python 动画流畅?
How to make my python animation smooth?
我正在使用 vispy
生成 3D 海 surface.But 不是很好 smooth.I 不知道我应该做哪一部分 improve.Can 谁能告诉我?这是代码:
from numpy import linspace,zeros,sin,pi,exp,sqrt
from vispy import app,scene
import sys
from vispy.util.filter import gaussian_filter
def I(x, y):
return exp(-(x-Lx/2.0)**2/2.0 -(y-Ly/2.0)**2/2.0)
def f(x, y, t):
return sin(2*x*y*pi*t/Lx) #defined by myself
def bc(x, y, t):
return 0.0
def solver0(I, f, c, bc, Lx, Ly, nx, ny, dt, t, user_action=None):
dx = Lx/float(nx)
dy = Ly/float(ny)
x = linspace(0, Lx, nx+1) #grid points in x dir
y = linspace(0, Ly, ny+1) #grid points in y dir
if dt <= 0: #max time step?
dt = (1/float(c))*(1/sqrt(1/dx**2 + 1/dy**2))
Cx2 = (c*dt/dx)**2
Cy2 = (c*dt/dy)**2 #help variables
dt2 = dt**2
up = zeros((nx+1,ny+1)) #solution array
u = up.copy() #solution at t-dt
um = up.copy() #solution at t-2*dt
#set initial condition:
#t =0.0
for i in range(0,nx):
for j in range(0,ny):
u[i,j] = I(x[i], y[j])
for i in range(1,nx-1):
for j in range(1,ny-1):
um[i,j] = u[i,j] + \
0.5*Cx2*(u[i-1,j] - 2*u[i,j] + u[i+1,j]) + \
0.5*Cy2*(u[i,j-1] - 2*u[i,j] + u[i,j+1]) + \
dt2*f(x[i], y[j], t)
#boundary values of um (equals t=dt when du/dt=0)
i = 0
for j in range(0,ny): um[i,j] = bc(x[i], y[j], t+dt)
j = 0
for i in range(0,nx): um[i,j] = bc(x[i], y[j], t+dt)
i = nx
for j in range(0,ny): um[i,j] = bc(x[i], y[j], t+dt)
j = ny
for i in range(0,nx): um[i,j] = bc(x[i], y[j], t+dt)
if user_action is not None:
user_action(u, x, y, t) #allow user to plot etc.
while t <= tstop:
t_old = t
t += dt
#update all inner points:
for i in range(1,nx-1):
for j in range(1,ny-1):
up[i,j] = -um[i,j] + 2*u[i,j] + \
Cx2*(u[i-1,j] - 2*u[i,j] + u[i+1,j]) + \
Cy2*(u[i,j-1] - 2*u[i,j] + u[i,j+1]) + \
dt2*f(x[i], y[j], t_old)
#insert boundary conditions:
i = 0
for j in range(0,ny): up[i,j] = bc(x[i], y[j], t)
j = 0
for i in range(0,nx): up[i,j] = bc(x[i], y[j], t)
i = nx
for j in range(0,ny): up[i,j] = bc(x[i], y[j], t)
j = ny
for i in range(0,nx): up[i,j] = bc(x[i], y[j], t)
if user_action is not None:
user_action(up, x, y, t)
um, u, up = u, up, um #update data structures
return up #dt might be computed in this function
Lx = 10
Ly = 10
c = 1.0
dt = 0
nx = 40
ny = 40
tstop = 20
x = linspace(0, Lx, nx+1) #grid points in x dir
y = linspace(0, Ly, ny+1) #grid points in y dir
canvas = scene.SceneCanvas(keys='interactive')
view = canvas.central_widget.add_view()
view.camera = scene.TurntableCamera(up='z')
p1 = scene.visuals.SurfacePlot(z=solver0(I, f, c, bc, Lx, Ly, nx, ny, dt, 0, user_action=None),color=(0,0,1,1),shading='smooth')
p1.transform = scene.transforms.AffineTransform()
p1.transform.scale([1/29.,1/29.,1.0])
p1.transform.translate([-1.0,-0.5,0])
view.add(p1)
t = 0.0
def update(ev):
global p1
global t
t += 1.0
p1.set_data(z=solver0(I, f, c, bc, Lx, Ly, nx, ny, dt, t, user_action=None))
timer = app.Timer()
timer.connect(update)
timer.start(0)
if __name__ == '__main__':
canvas.show()
if sys.flags.interactive == 0:
app.run()
试试这个:
up[1:nx-1,1:nx-1]=-um[1:nx-1,1:ny-1]+2*u[1:nx-1,1:ny-1]+ \
Cx2*(u[0:nx-2,1:ny-1]-2*u[1:nx-1,1:ny-1]+ u[2:nx,1:ny-1]) + \
Cy2*(u[1:nx-1,0:ny-2]-2*u[1:nx-1,1:ny-1]+ u[1:nx-1,2:ny]) + \
[[dt2*f(x[i],y[j],t_old) for i in range(1,nx-1)] for j in range(1,ny-1)]
而不是
#update all inner points:
for i in range(1,nx-1):
for j in range(1,ny-1):
up[i,j] = -um[i,j] + 2*u[i,j] + \
Cx2*(u[i-1,j] - 2*u[i,j] + u[i+1,j]) + \
Cy2*(u[i,j-1] - 2*u[i,j] + u[i,j+1]) + \
dt2*f(x[i], y[j], t_old)
切片在 Python 中非常快,列表推导也是如此。我基本上通过添加矩阵在单个表达式中计算整个双 for 循环。
如有错误告诉我(可能是故意错误)
编辑:一些错误的索引,用一些组成的矩阵在 100 次运行中测试了这个;我的变体比双 for 循环快大约 10 倍。您可以用类似的方式更改程序中的其他双循环。
编辑:
List Comprehensions 几乎总是比 for 循环更快,所以
for j in range(0,ny): up[i,j] = bc(x[i], y[j], t)
写
up[i,0:ny] = [bc(x[i],y[j],t) for j in range(0,ny)]
这应该会快一点
此外,如果您使用 python 2.7,请使用 xrange 而不是 range 以节省内存。
以下是如何将 for 循环转换为列表理解的更多示例:
http://www.u.arizona.edu/~erdmann/mse350/topics/list_comprehensions.html
一开始有点复杂,但绝对值得!
我正在使用 vispy
生成 3D 海 surface.But 不是很好 smooth.I 不知道我应该做哪一部分 improve.Can 谁能告诉我?这是代码:
from numpy import linspace,zeros,sin,pi,exp,sqrt
from vispy import app,scene
import sys
from vispy.util.filter import gaussian_filter
def I(x, y):
return exp(-(x-Lx/2.0)**2/2.0 -(y-Ly/2.0)**2/2.0)
def f(x, y, t):
return sin(2*x*y*pi*t/Lx) #defined by myself
def bc(x, y, t):
return 0.0
def solver0(I, f, c, bc, Lx, Ly, nx, ny, dt, t, user_action=None):
dx = Lx/float(nx)
dy = Ly/float(ny)
x = linspace(0, Lx, nx+1) #grid points in x dir
y = linspace(0, Ly, ny+1) #grid points in y dir
if dt <= 0: #max time step?
dt = (1/float(c))*(1/sqrt(1/dx**2 + 1/dy**2))
Cx2 = (c*dt/dx)**2
Cy2 = (c*dt/dy)**2 #help variables
dt2 = dt**2
up = zeros((nx+1,ny+1)) #solution array
u = up.copy() #solution at t-dt
um = up.copy() #solution at t-2*dt
#set initial condition:
#t =0.0
for i in range(0,nx):
for j in range(0,ny):
u[i,j] = I(x[i], y[j])
for i in range(1,nx-1):
for j in range(1,ny-1):
um[i,j] = u[i,j] + \
0.5*Cx2*(u[i-1,j] - 2*u[i,j] + u[i+1,j]) + \
0.5*Cy2*(u[i,j-1] - 2*u[i,j] + u[i,j+1]) + \
dt2*f(x[i], y[j], t)
#boundary values of um (equals t=dt when du/dt=0)
i = 0
for j in range(0,ny): um[i,j] = bc(x[i], y[j], t+dt)
j = 0
for i in range(0,nx): um[i,j] = bc(x[i], y[j], t+dt)
i = nx
for j in range(0,ny): um[i,j] = bc(x[i], y[j], t+dt)
j = ny
for i in range(0,nx): um[i,j] = bc(x[i], y[j], t+dt)
if user_action is not None:
user_action(u, x, y, t) #allow user to plot etc.
while t <= tstop:
t_old = t
t += dt
#update all inner points:
for i in range(1,nx-1):
for j in range(1,ny-1):
up[i,j] = -um[i,j] + 2*u[i,j] + \
Cx2*(u[i-1,j] - 2*u[i,j] + u[i+1,j]) + \
Cy2*(u[i,j-1] - 2*u[i,j] + u[i,j+1]) + \
dt2*f(x[i], y[j], t_old)
#insert boundary conditions:
i = 0
for j in range(0,ny): up[i,j] = bc(x[i], y[j], t)
j = 0
for i in range(0,nx): up[i,j] = bc(x[i], y[j], t)
i = nx
for j in range(0,ny): up[i,j] = bc(x[i], y[j], t)
j = ny
for i in range(0,nx): up[i,j] = bc(x[i], y[j], t)
if user_action is not None:
user_action(up, x, y, t)
um, u, up = u, up, um #update data structures
return up #dt might be computed in this function
Lx = 10
Ly = 10
c = 1.0
dt = 0
nx = 40
ny = 40
tstop = 20
x = linspace(0, Lx, nx+1) #grid points in x dir
y = linspace(0, Ly, ny+1) #grid points in y dir
canvas = scene.SceneCanvas(keys='interactive')
view = canvas.central_widget.add_view()
view.camera = scene.TurntableCamera(up='z')
p1 = scene.visuals.SurfacePlot(z=solver0(I, f, c, bc, Lx, Ly, nx, ny, dt, 0, user_action=None),color=(0,0,1,1),shading='smooth')
p1.transform = scene.transforms.AffineTransform()
p1.transform.scale([1/29.,1/29.,1.0])
p1.transform.translate([-1.0,-0.5,0])
view.add(p1)
t = 0.0
def update(ev):
global p1
global t
t += 1.0
p1.set_data(z=solver0(I, f, c, bc, Lx, Ly, nx, ny, dt, t, user_action=None))
timer = app.Timer()
timer.connect(update)
timer.start(0)
if __name__ == '__main__':
canvas.show()
if sys.flags.interactive == 0:
app.run()
试试这个:
up[1:nx-1,1:nx-1]=-um[1:nx-1,1:ny-1]+2*u[1:nx-1,1:ny-1]+ \
Cx2*(u[0:nx-2,1:ny-1]-2*u[1:nx-1,1:ny-1]+ u[2:nx,1:ny-1]) + \
Cy2*(u[1:nx-1,0:ny-2]-2*u[1:nx-1,1:ny-1]+ u[1:nx-1,2:ny]) + \
[[dt2*f(x[i],y[j],t_old) for i in range(1,nx-1)] for j in range(1,ny-1)]
而不是
#update all inner points:
for i in range(1,nx-1):
for j in range(1,ny-1):
up[i,j] = -um[i,j] + 2*u[i,j] + \
Cx2*(u[i-1,j] - 2*u[i,j] + u[i+1,j]) + \
Cy2*(u[i,j-1] - 2*u[i,j] + u[i,j+1]) + \
dt2*f(x[i], y[j], t_old)
切片在 Python 中非常快,列表推导也是如此。我基本上通过添加矩阵在单个表达式中计算整个双 for 循环。
如有错误告诉我(可能是故意错误)
编辑:一些错误的索引,用一些组成的矩阵在 100 次运行中测试了这个;我的变体比双 for 循环快大约 10 倍。您可以用类似的方式更改程序中的其他双循环。
编辑:
List Comprehensions 几乎总是比 for 循环更快,所以
for j in range(0,ny): up[i,j] = bc(x[i], y[j], t)
写
up[i,0:ny] = [bc(x[i],y[j],t) for j in range(0,ny)]
这应该会快一点 此外,如果您使用 python 2.7,请使用 xrange 而不是 range 以节省内存。
以下是如何将 for 循环转换为列表理解的更多示例: http://www.u.arizona.edu/~erdmann/mse350/topics/list_comprehensions.html
一开始有点复杂,但绝对值得!