2016-03-02 2 views
1

Я использую vispy для создания 3D-поверхности моря. Но это не очень гладко. Я не знаю, какую часть я должен улучшить. Кто-нибудь может мне сказать? Вот код:Как сделать мою анимацию python гладкой?

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() 

ответ

1

Попробуйте использовать это:

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 и так описаний списков. Я в основном вычисляю весь цикл double для цикла в одном выражении, добавляя матрицы.

Сообщите мне, если есть какие-либо ошибки (Там могут быть ошибки intendation)

EDIT: некоторые неправильные показатели, протестированные это в 100 пробегов с некоторыми составленных матриц; Мой вариант примерно в 10 раз быстрее, чем двойной цикл. Аналогичным образом вы можете изменить другую двойную форму для петель в своей программе.

EDITEDIT:

списковых почти всегда быстрее, чем для петель, так что вместо

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 вместо диапазона для сохранения памяти.

Вот еще несколько примеров, как превратить для петель в списковых: http://www.u.arizona.edu/~erdmann/mse350/topics/list_comprehensions.html

Это немного сложно в первый, но определенно стоит!

+0

Это действительно становится более плавным после изменения двойника для цикла. Я новая рыба, и я даже не знаю этого раньше. Большое вам спасибо за ваш совет. Является ли это единственной частью, которую я могу улучшить? Должен ли я что-то делать с моим одиночным циклом? –

+0

Я знаю только о разрезе, потому что я использовал его в сотовых автоматах;) Но вы должны читать в списках, они просто намного быстрее. Я отредактирую ответ, чтобы добавить список comps для ваших одиночных циклов. Дай мне минуту. Вы можете заглянуть в это за это время: https://wiki.python.org/moin/PythonSpeed/PerformanceTips – JeD

+0

Большое спасибо :) –

Смежные вопросы