前向和后向集成——错误的原因

计算科学 Python scipy 符号计算 智者
2021-12-15 17:49:38

我编写了一个测试程序,在上向前积分,然后从哈密顿系统的正向积分端点向后积分 的表达式(在下面的程序中给出并不重要)。[0,Tf][Tf,0]

q˙(t)=Hp(q(t),p(t)),p˙(t)=Hq(q(t),p(t))
H

我使用SageMath象征性地计算动力学的哈密顿量和雅可比的导数我使用scipy python 库的“dopri5”例程进行数值积分。

该程序做了我们想要的,但是有一些数字错误,因为我们没有得到我们开始的确切初始值,我认为这些错误来自积分器?我们看到中间点 (zmid) 的顺序是 +1e12,所以它会导致错误,但其他原因可能是什么?

为了更加准确和准确,我修改了以下设置:

  • 减少“dopri5”例程的atolrtol和增加nsteps

您对提高方法的精密度和准确度有更多建议吗?从数学的角度来看,这些错误的原因是什么?例如,如果我们在动力学中有不同的时间尺度......

from scipy.integrate import ode
from sage.all import *

#Dimension of the state variables
N=2
#Final time
Tf = 10.
#Symbolic variables of the Hamiltonian
var('q1 q2 p1 p2 v')
qs = [q1,q2]
ps = [p1,p2]
zs = qs + ps

#Hamiltonian function and jacobian of the dynamics
def hfun():
    H = p1*(cos(q1^2)+1/3*sin(q2)^2) + p2*(cos(q1)-2*sin(q2*q1)^2)
    dHdp = jacobian(H,ps)
    dHdq = jacobian(H,qs)
    matzdot=block_matrix(SR,[[dHdp.T],[-dHdq.T]])
    jaczdot = jacobian(matzdot,zs)
    return H, jaczdot

#Hamiltonian dynamics
def dynz(t,z):
    H,aux = hfun()
    jacHp = jacobian(H,ps)
    jacHp = list(jacHp[0].subs({zs[i]:z[i] for i in range(0,2*N)}))
    dzdt = jacHp
    jacHq = jacobian(H,qs)
    dzdt.extend(list(-jacHq[0].subs({zs[i]:z[i] for i in range(0,2*N)})))
    return dzdt

#integration
def main():
    z0 = [1.,-0.5,-2.,1.]
    print("z0: ")
    print(z0)

    solverz = ode(dynz).set_integrator('dopri5')
    solverz.set_initial_value(z0,0.)
    solverz.integrate(Tf)

    zf = solverz.y
    print("zmid: ")
    print(zf)

    solverz.set_initial_value(zf,Tf)
    solverz.integrate(0.)
    print("z0: ")
    print(solverz.y)

    return solverz.y


main()

这是输出:

z0: 
[1.00000000000000, -0.500000000000000, -2.00000000000000, 1.00000000000000]
zmid: 
[ 1.35249010e+00 -2.07489135e+00 -3.88286701e+12  8.51614447e+11]
z0: 
[ 0.99956526 -0.50018124 -2.00172766  1.00161313]
1个回答

您对提高方法的精密度和准确度有更多建议吗?从数学的角度来看,这些错误的原因是什么?例如,如果我们在动力学中有不同的时间尺度......

如果要执行此操作,则需要使用可逆 ODE 求解器方法。实际上,我最近在一篇博客文章中表明,在很多情况下,如果没有可逆积分器,你可以预期它会失败,例如在求解 Lorenz 方程时。

关于时间可逆方法有很多资源:

最好的来源可能是 Hairer 的 Geometric Numerical Integration 书,它几乎在所有方面都进行了详细介绍,我强烈建议您阅读一下。基本上,仅仅因为数值方法是一致的(一步中的误差为零)并不意味着该方法是稳定的(误差不会随着时间的推移而增长)。

辛方法是可逆的,但也有非辛方法也是可逆的(梯形)。可逆性还要求以对称的方式选择时间步集,这基本上排除了任何自适应积分。在哈密顿系统上可以有一些额外的优势,所以你可能正在寻找一个辛积分器。

SciPy 不包括任何可逆积分器,并且确实具有关闭自适应积分的能力。Harier 确实有一些用于辛积分器的 Fortran 代码,但我不确定是否有任何 Python 绑定。GSL有一些,但再次不确定 Python 绑定。DifferentialEquations.jl有大量辛积分器,以及一种通过 diffeqpy 从 Python 使用它的方法。您只需使用 DiffEqPhysics 中的 HamiltonianProblem即可直接定义供辛积分器使用的问题可以在教程中找到有关使用这些的一个很好的资源,并且要从 diffeqpy 使用它,您基本上只需附加de.在包调用上。


脚注:由于NeurIPS 的一篇获奖论文,这种进行反向集成的想法最近似乎在深度学习和概率编程圈中流行起来,用于计算伴随项,但你应该三思而后行,因为它并不稳定!相反,应该使用一个系统,其中伴随的计算只需要前向传递,就像在DifferentialEquations.jlSUNDIALS中通过检查点或插值完成的那样。因此,如果您要计算 Hamltionian Monte Carlo (HMC) 的伴随,请记住这一点。