弹簧质点系统仅 6 FPS?

运行环境

C:\ProgramData\Anaconda3\envs\taichi_learn\python.exe D:/PycharmProjects/taichi_learn/--Deformables-master/mass-spring-explicit.py
[Taichi] version 1.0.4, llvm 10.0.0, commit 2827db2c, win, python 3.10.4
[Taichi] Starting on arch=cuda

问题描述

在Windows 10, RTX3090 上运行示例代码,仅 6 FPS。请问是正常的吗?不正常的话,该如何寻找原因呢?多谢

代码链接

Hi @Roden ,慢的一个原因是你虽然计算部分使用了CUDA,但是显示部分用的GUI。这需要将GPU数据从显存拷贝到内存。如果直接用arch=ti.cpu速度会快一点。 或者将GUI替换为GGUI,速度应该也会更快。

默认确实是cpu,但是也只有12FPS。所以ti.GUI是只用了CPU来渲染吗?

有些参数变了,我看下文档试一下GGUI

我修改成GGUI之后,报错

Exception: unrecognized event tag
GLFW Error 65537: The GLFW library is not initialized

详细 log 如下

C:\ProgramData\Anaconda3\envs\taichi_learn\python.exe D:/PycharmProjects/taichi_learn/--Deformables-master/mass-spring-explicit.py
[Taichi] version 1.0.4, llvm 10.0.0, commit 2827db2c, win, python 3.10.4
[Taichi] Starting on arch=cuda
[I 07/24/22 17:09:59.425 10592] [D:/a/taichi/taichi/taichi/rhi/vulkan/vulkan_device_creator.cpp:pick_physical_device@364] Found Vulkan Device 0 (NVIDIA GeForce RTX 3090)
[I 07/24/22 17:09:59.425 10592] [D:/a/taichi/taichi/taichi/rhi/vulkan/vulkan_device_creator.cpp:find_queue_families@142] Async compute queue 2, graphics queue 0
[I 07/24/22 17:09:59.425 10592] [D:/a/taichi/taichi/taichi/rhi/vulkan/vulkan_device_creator.cpp:find_queue_families@142] Async compute queue 2, graphics queue 0
[I 07/24/22 17:09:59.425 10592] [D:/a/taichi/taichi/taichi/rhi/vulkan/vulkan_device_creator.cpp:create_logical_device@432] Vulkan Device "NVIDIA GeForce RTX 3090" supports Vulkan 0 version 1.2.186
Traceback (most recent call last):
  File "D:\PycharmProjects\taichi_learn\--Deformables-master\mass-spring-explicit.py", line 187, in <module>
    for e in window.get_events(ti.GUI.PRESS):
  File "C:\ProgramData\Anaconda3\envs\taichi_learn\lib\site-packages\taichi\ui\window.py", line 71, in get_events
    raise Exception("unrecognized event tag")
Exception: unrecognized event tag
GLFW Error 65537: The GLFW library is not initialized

根据这里,我去跑了一下mass_spring_3d_ggui.py,是可以运行的。布料打到球上面,有60FPS。这样来看整个系统配置应该是正常的?

我更改后的代码

import taichi as ti
import math

ti.init(arch=ti.gpu)

# global control
paused = True
damping_toggle = ti.field(ti.i32, ())
curser = ti.Vector.field(2, ti.f32, ())
picking = ti.field(ti.i32,())

# integration method
# 1: explicit euler
# 2: symplectic euler
# 3: implicit euler (you bet)
integration = 2

# procedurally setting up the cantilever
init_x, init_y = 0.1, 0.6
N_x = 20
N_y = 4
# N_x = 2
# N_y = 2
N = N_x*N_y
N_edges = (N_x-1)*N_y + N_x*(N_y - 1) + (N_x-1) * \
    (N_y-1)  # horizontal + vertical + diagonal springs
N_triangles = 2 * (N_x-1) * (N_y-1)
dx = 1/32
curser_radius = dx/2

# physical quantities
m = 1
g = 9.8
YoungsModulus = ti.field(ti.f32, ())

# time-step size (for simulation, 16.7ms)
h = 16.7e-3
# substepping
substepping = 100
# time-step size (for time integration)
dh = h/substepping

# simulation components
x = ti.Vector.field(2, ti.f32, N)
v = ti.Vector.field(2, ti.f32, N)
grad = ti.Vector.field(2, ti.f32, N)
spring_length = ti.field(ti.f32, N_edges)

# geometric components
triangles = ti.Vector.field(3, ti.i32, N_triangles)
edges = ti.Vector.field(2, ti.i32, N_edges)

@ti.func
def ij_2_index(i, j): return i * N_y + j

# -----------------------meshing and init----------------------------
@ti.kernel
def meshing():
    # setting up triangles
    for i,j in ti.ndrange(N_x - 1, N_y - 1):
        # triangle id
        tid = (i * (N_y - 1) + j) * 2
        triangles[tid][0] = ij_2_index(i, j)
        triangles[tid][1] = ij_2_index(i + 1, j)
        triangles[tid][2] = ij_2_index(i, j + 1)

        tid = (i * (N_y - 1) + j) * 2 + 1
        triangles[tid][0] = ij_2_index(i, j + 1)
        triangles[tid][2] = ij_2_index(i + 1, j + 1)
        triangles[tid][1] = ij_2_index(i + 1, j)

    # setting up edges
    # edge id
    eid_base = 0

    # horizontal edges
    for i in range(N_x-1):
        for j in range(N_y):
            eid = eid_base+i*N_y+j
            edges[eid] = [ij_2_index(i, j), ij_2_index(i+1, j)]

    eid_base += (N_x-1)*N_y
    # vertical edges
    for i in range(N_x):
        for j in range(N_y-1):
            eid = eid_base+i*(N_y-1)+j
            edges[eid] = [ij_2_index(i, j), ij_2_index(i, j+1)]

    eid_base += N_x*(N_y-1)
    # diagonal edges
    for i in range(N_x-1):
        for j in range(N_y-1):
            eid = eid_base+i*(N_y-1)+j
            edges[eid] = [ij_2_index(i+1, j), ij_2_index(i, j+1)]


@ti.kernel
def initialize():
    YoungsModulus[None] = 3e4
    paused = True
    # init position and velocity
    for i, j in ti.ndrange(N_x, N_y):
        index = ij_2_index(i, j)
        x[index] = ti.Vector([init_x + i * dx, init_y + j * dx])
        v[index] = ti.Vector([0.0, 0.0])

@ti.kernel
def initialize_springs():
    # init spring rest-length
    for i in range(N_edges):
        a, b = edges[i][0], edges[i][1]
        r = x[a]-x[b]
        spring_length[i] = r.norm()

# ----------------------core-----------------------------
@ti.kernel
def compute_gradient():
    # clear gradient
    for i in grad:
        grad[i] = ti.Vector([0, 0])

    # gradient of elastic potential
    for i in range(N_edges):
        a, b = edges[i][0], edges[i][1]
        r = x[a]-x[b]
        l = r.norm()
        l0 = spring_length[i]
        k = YoungsModulus[None]/l0  # stiffness in Hooke's law
        gradient = k*(l-l0)*r/l
        grad[a] += gradient
        grad[b] += -gradient

@ti.kernel
def update():
    # perform time integration
    for i in range(N):
        if integration == 1:
            # explicit euler integration
            x[i] += dh*v[i]   
            # elastic force + gravitation force, divding mass to get the acceleration
            acc = -grad[i]/m - ti.Vector([0.0, g])
            v[i] += dh*acc
        elif integration == 2:        
            # symplectic integration
            # elastic force + gravitation force, divding mass to get the acceleration
            acc = -grad[i]/m - ti.Vector([0.0, g])
            v[i] += dh*acc
            x[i] += dh*v[i]

    # explicit damping (ether drag)
    for i in v:
        if damping_toggle[None]:
            v[i] *= ti.exp(-dh*5)

    # enforce boundary condition
    for i in range(N):
        if picking[None]:           
            r = x[i]-curser[None]
            if r.norm() < curser_radius:
                x[i] = curser[None]
                v[i] = ti.Vector([0.0, 0.0])
                pass

    for j in range(N_y):
        ind = ij_2_index(0, j)
        v[ind] = ti.Vector([0, 0])
        x[ind] = ti.Vector([init_x, init_y + j * dx])  # rest pose attached to the wall

    for i in range(N):
        if x[i][0] < init_x:
            x[i][0] = init_x
            v[i][0] = 0


# init once and for all
meshing()
initialize()
initialize_springs()

window = ti.ui.Window('mass-spring system', (800, 800))

while window.running:

    picking[None]=0

    # key events
    for e in window.get_events(ti.GUI.PRESS):
        if e.key in [ti.GUI.ESCAPE, ti.GUI.EXIT]:
            exit()
        elif e.key == 'r':
            initialize()
        elif e.key == '0':
            YoungsModulus[None] *= 1.1
        elif e.key == '9':
            YoungsModulus[None] /= 1.1
        elif e.key == ti.GUI.SPACE:
            paused = not paused
        elif e.key =='d' or e.key == 'D':
            damping_toggle[None] = not damping_toggle[None]
        elif e.key == 'p' or e.key == 'P':
            for i in range(substepping):
                compute_gradient()
                update()           

    if window.is_pressed(ti.GUI.LMB):
        curser[None] = window.get_cursor_pos()
        picking[None] = 1

    # numerical time integration
    if not paused:
        for i in range(substepping):
            compute_gradient()
            update()

    # render
    pos = x.to_numpy()
    for i in range(N_edges):
        a, b = edges[i][0], edges[i][1]
        window.line((pos[a][0], pos[a][1]),
                 (pos[b][0], pos[b][1]),
                 radius=1,
                 color=0xFFFF00)
    window.line((init_x, 0.0), (init_x, 1.0), color=0xFFFFFF, radius=4)

    if picking[None]:
        window.circle((curser[None][0], curser[None][1]), radius=curser_radius*800, color=0xFF8888)

    # text
    window.text(
        content=f'9/0: (-/+) Young\'s Modulus {YoungsModulus[None]:.1f}', pos=(0.6, 0.9), color=0xFFFFFF)
    if damping_toggle[None]:
        window.text(
            content='D: Damping On', pos=(0.6, 0.875), color=0xFFFFFF)
    else:
        window.text(
            content='D: Damping Off', pos=(0.6, 0.875), color=0xFFFFFF)
    window.show()

你的事件处理那里使用的 ti.GUI.ESCAPE 之类的都是给 GUI 使用的,GGUI 要用 ti.ui.ESCAPE.

1 Like