1

3D海面の生成に使っvispyていますが、あまり滑らかではありません。どこを改善すればいいのかわかりません。誰か教えていただけませんか?コードは次のとおりです。

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

1 に答える 1

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 for ループ全体を計算します。

エラーがあれば教えてください(意図的なエラーがあるかもしれません)

編集:いくつかの間違ったインデックス、いくつかの構成された行列で100回の実行でこれをテストしました。私のバリアントは、二重の for ループよりも約 10 倍高速です。同様の方法で、プログラム内の他の double for ループを変更できます。

編集編集:

リスト内包表記は、ほとんどの場合、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 を使用している場合は、range の代わりに xrange を使用してメモリを節約してください。

for ループをリスト内包表記に変換する方法の例をいくつか次に示します

最初は少し複雑ですが、間違いなく価値があります。

于 2016-03-02T15:57:48.883 に答える