Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Fortran中Verlet算法的错误顺序_Fortran_Numerical Methods - Fatal编程技术网

Fortran中Verlet算法的错误顺序

Fortran中Verlet算法的错误顺序,fortran,numerical-methods,Fortran,Numerical Methods,我试图用Fortran中的Verlet方法(原始Verlet)来模拟谐振子。 我的研究表明误差的顺序应该是2,但我的计算表明误差的顺序是1 我在源代码中找不到我的错误。我该怎么办 编辑: 我使用的算法如下: x(t+Δt) = 2x(t) - x(t-Δt) + Δt² F(t)/m v(t) = {x(t+Δt) -x(t-Δt)}/2Δt 其中x(t)表示位置,v(t)表示速度,F(t)表示力。我知道这是描述的原始Verlet 根据,错误的顺序应至少为O(Δt²),但在gnuplot(下

我试图用Fortran中的Verlet方法(原始Verlet)来模拟谐振子。 我的研究表明误差的顺序应该是2,但我的计算表明误差的顺序是1

我在源代码中找不到我的错误。我该怎么办

编辑: 我使用的算法如下:

x(t+Δt) = 2x(t) - x(t-Δt) + Δt² F(t)/m

v(t) = {x(t+Δt) -x(t-Δt)}/2Δt
其中x(t)表示位置,v(t)表示速度,F(t)表示力。我知道这是描述的原始Verlet

根据,错误的顺序应至少为O(Δt²),但在gnuplot(下面)中绘制的程序顺序的错误没有O(Δt²)的顺序

上面的程序计算时间步长h的计算误差。

根据Verlet积分器的计算公式,我们似乎需要使用更精确的方法来设置初始值xold(即包括力的项),以获得2阶的全局误差。实际上,如果我们将
xold
修改为

program newton_verlet
implicit none
real*16, parameter :: DT   = 3.0
real*16, parameter :: M    = 1.0
real*16, parameter :: X0   = 1.0
real*16, parameter :: V0   = 0.0

real*16 x,v,xold,xnew,f,h
integer it,n

do n = 0, 20

    h = DT / 2**n

    x = X0
    v = V0
    f = -x

    ! xold = x - v * h                     !! original
    xold = x - v * h + f * h**2 / (2 * M)  !! modified

    do it = 1, 2**n

        f = -x

        xnew = 2 * x - xold + f * h * h / M

        xold = x
        x = xnew
    end do

    write(*,*) log10( h ), log10( abs(x - cos(DT)) )
end do

end program
全局错误的顺序为2(请参见下面的日志图)


如果力是
x
的函数,并且是势能函数的负梯度,则Verlet方法仅适用于所有声称的特性。这意味着它应该是
F(x(t))
。我很想知道
real128
(real*16)相对于双精度
real64
的需要。仅此一项就可能使代码的运行时间增加一倍以上。而且,
real*16
不符合Fortran标准。一种正式的方法是
仅使用iso_fortran_env:real128
并将实变量声明为
real128
@IanBush是的,我认为你是对的。。虽然我试图强调关键修改部分(而不更改其他部分),但我将在下面为OP添加一个链接。@MaoNishino如上所述,real*16不可移植,因此建议使用KIND机制;例如,请参见此Q/A作为起点:另外,请注意,“1.23”等表示默认实数类型(通常为32位)。我们可以指定这样一个文本的种类,如1.23_dp等(其中dp是一个种类参数)。
program newton_verlet
implicit none
real*16, parameter :: DT   = 3.0
real*16, parameter :: M    = 1.0
real*16, parameter :: X0   = 1.0
real*16, parameter :: V0   = 0.0

real*16 x,v,xold,xnew,f,h
integer it,n

do n = 0, 20

    h = DT / 2**n

    x = X0
    v = V0
    f = -x

    ! xold = x - v * h                     !! original
    xold = x - v * h + f * h**2 / (2 * M)  !! modified

    do it = 1, 2**n

        f = -x

        xnew = 2 * x - xold + f * h * h / M

        xold = x
        x = xnew
    end do

    write(*,*) log10( h ), log10( abs(x - cos(DT)) )
end do

end program