Fortran的龙格库塔

时间:2017-05-21 15:18:23

标签: fortran fortran90 runge-kutta

我正在尝试在Fortran中实现Runge Kutta方法,并且面临收敛问题。我不知道我应该展示多少代码,所以我会详细描述这个问题,并请指导我应该在帖子中添加/删除哪些内容以使其可以回复。

我有一个球的位置和速度的六维向量,以及相应的差异系统。公式。描述运动方程,我想从中计算球的轨迹,并比较RK方法的不同阶数的结果。

让我们关注三阶RK。我使用的模型实现如下:

k1 = h * f(vec_old,omega,phi)
k2 = h * f(vec_old + 0.5d0 * k1,omega,phi)
k3 = h * f(vec_old + 2d0 * k2 - k1,omega,phi)
vec = vec_old + (k1 + 4d0 * k2 + k3) / 6d0

其中f是构成运动方程的函数(或者等同于我的diff.eqs系统的RHS)。请注意,f与时间无关,因此只有一个参数。 h扮演一个小时间步的角色。

如果我们希望在有限时间total_time内计算球的轨迹,并允许总误差为epsilon,那么我们需要确保每个步骤都采用误差的比例分数。第一步,我做了以下事情:

vec1 = solve(3,vec_old,h,omega,phi)
vec2 = solve(3,vec_old,h/2d0,omega,phi)
do while (maxval((/(abs(vec1(i) - vec2(i)),i=1,6)/)) > eps * h / (tot_time - current_time))
    h = h / 2d0
    vec1 = solve(3,vec_old,h,omega,phi)
    vec2 = solve(3,vec_old,h/2d0,omega,phi)
end do
vec = (8d0/7d0) * vec2 - (1d0/7d0) * vec1

其中solve(3,vec_old,h,omega,phi)是计算上述单个RK步骤的函数。 3表示我们正在使用的RK顺序,vec_old是位置 - 速度向量的当前状态,h, h/2d0都表示正在使用的时间步长,而omega,phi只是f的一些额外参数。最后,我们设置current_time = 0d0

的第一步

关键是如果我们使用3阶RK,我们应该在$ O(h ^ 3)$中出错,因此在h中线性地下降得更快。因此,我们应该期望while循环最终会停止,足够小h

我的问题是循环没有收敛,甚至没有收敛 - 比率

maxval(...) / eps * (...)
由于精度有限,

一直保持不变,直到eps * h / (tot_time - current_time))变为零。

为了完整起见,这是我对f的定义:

function f(vec_old,omega,phi) result(vec)
    real(8),intent(in) :: vec_old(6),omega,phi
    real(8) :: vec(6)
    real(8) :: v,Fv

    v = sqrt(vec_old(4)**2+vec_old(5)**2+vec_old(6)**2)
    Fv = 0.0039d0 + 0.0058d0 / (1d0 + exp((v-35d0)/5d0))
    vec(1) = vec_old(4)
    vec(2) = vec_old(5)
    vec(3) = vec_old(6)
    vec(4) = -Fv * v * vec_old(4) + 4.1d-4 * omega * (vec_old(6)*sin(phi) - vec_old(5)*cos(phi))
    vec(5) = -Fv * v * vec_old(5) + 4.1d-4 * omega * vec_old(4)*cos(phi)
    vec(6) = -Fv * v * vec_old(6) - 4.1d-4 * omega * vec_old(4)*sin(phi) - 9.8d0
end function f

有没有人知道为什么while循环不会收敛? 如果需要其他任何东西(输出,其他代码等),请告诉我,我会添加它。此外,如果需要修剪,我会削减任何不必要的东西。谢谢!

1 个答案:

答案 0 :(得分:1)

要使用半步法计算步误差,您需要在两种情况下计算t+h处的近似值,这意味着步长为h/2的两个步骤。现在,您可以将t+h的近似值与t+h/2的近似值进行比较,从而得出大小为f(vec(t+h/2))*h/2的错误。

因此改为三步程序

vec1 = solve(3,vec_old,h,omega,phi)
vec2 = solve(3,vec_old,h/2d0,omega,phi)
vec2 = solve(3,vec2   ,h/2d0,omega,phi)

在这两个位置,vec2-vec1的差异应该是h^4的顺序。