关于积分解PDE的问题

本人编程小白。最近在把之前写的解偏微分的代码重写成taichi,发现了两个问题:

第一,同样的公式数据计算结果与之前写的python代码的结果,和解析解相差很大。我演算了初始5次iteration中的微分du/dt结果正常,之后的微分值就和解析解差很多了。我不太清楚这是因为我的公式的问题还是其他原因。
第二,我发现同一个解微分方程的程序,每次运算出的结果都有不同,偶尔会出现完全错误的结果。这种现象正常吗?

最后附上代码,请带哥们不吝赐教!

import numpy as np
import taichi as ti
import time


ti.init(arch=ti.cpu, default_fp=ti.f32, dynamic_index=True)


@ ti.kernel
def inti_main():
    t = 0.                                           # end time
    tmax = 0.01                                       # start time
    dt = ti.cast(0.000001,dtype=ti.f32)                                        # delta time
    dx = ti.cast(2/32, dtype=ti.f32)                                        # dx is prepared but unused in this case
    leng = ti.cast(tmax/dt, dtype=ti.i32)               # length of iteration---tmax/dt, better define manually
                                                     # 'leng' should be change along with the shape of field
    u = init_con
    for c in range(leng):
        u_new, t_new = runge_kutta_4(u, t, dt, dx)       # integration method, change manually---euler_f, runge_kutta_4
        field[c, 0] = u_new
        u = ti.cast(u_new, dtype=ti.f32)
        t = ti.cast(t_new, dtype=ti.f32)


@ ti.func
def euler_f(u, t, dt, dx):
    u_new = u + heat_equ(u, t, dx)*dt
    t_new = t + dt
    return u_new, t_new




@ ti.func
def runge_kutta_4(u, t, dt, dx):
    k0 = heat_equ(u, t, dx)
    k1 = heat_equ(u+(dt*k0/2.0), t+(dt/2.0), dx)
    k2 = heat_equ(u+(dt*k1/2.0), t+(dt/2.0), dx)
    k3 = heat_equ(u+dt*k2, t+dt, dx)
    return u + dt*(k0+(2.0*k1)+(2.0*k2)+k3)/6.0, t+dt

 

@ ti.func
def d2udx2(u, dx):
    d2u = ti.cast(dut, dtype=ti.f32)
    for i in range(1, 31):
        d2u[i] = (u[i+1]-2.*u[i]+u[i-1])/(dx**2.)
    #print(d2u)
    return d2u



@ ti.func
def heat_equ(u, t, dx, k=130.):
    res = k*d2udx2(u, dx)
    return res




field = ti.Vector.field(32, dtype=ti.f32, shape=(10000, 1))          # the compilation of all data points,
                                                                   # in which the 'row' dimension must be 
                                                                   # the same as 'leng' parameter 
ic = np.zeros(32)
ic[1:-1] = np.ones(30) 
init_con = ti.Vector(list(ic), dt=ti.f32)                   # global initial condition
d = ti.types.vector(32, ti.f32)                             # global derivatives template
dut = d(np.zeros(32))
print(init_con)

inti_main()


#result = np.array(field)
print(field[9999, 0])

Hi @Ruixiao_Liu , 非常欢迎来到Taichi论坛。

我看了下代码,你的inti_main 函数是个kernel函数,里面的for循环是并行的。而你要做的是从0时刻,一步一步的时间积分算出新的 u。所以,你可以在for循环前一行加上ti.loop_config(serialize=True),让它顺序执行再看看结果如何。

谢谢带哥,运行结果比python代码还准。