Fortran 阶跃校正Runge-Kutta方法的无限循环实现
我正在用阶跃校正程序实现常微分方程近似的龙格-库塔-4方法。 代码如下:Fortran 阶跃校正Runge-Kutta方法的无限循环实现,fortran,gfortran,numerical-methods,Fortran,Gfortran,Numerical Methods,我正在用阶跃校正程序实现常微分方程近似的龙格-库塔-4方法。 代码如下: function RK4 (v,h,cant_ec) !Runge-Kutta 4to Orden real(8),dimension(0:cant_ec)::RK4,v real::h integer::cant_ec real(8),dimension(0:cant_ec)::k1,k2,k3,k4 k1 = h*vprima(v) k2 = h*vprima(v+k
function RK4 (v,h,cant_ec) !Runge-Kutta 4to Orden
real(8),dimension(0:cant_ec)::RK4,v
real::h
integer::cant_ec
real(8),dimension(0:cant_ec)::k1,k2,k3,k4
k1 = h*vprima(v)
k2 = h*vprima(v+k1/2.0)
k3 = h*vprima(v+k2/2.0)
k4 = h*vprima(v+k3)
v = v + (k1+2.0*k2+2.0*k3+k4)/6.0 !la aproximación actual con paso h
RK4 = v
end function RK4
subroutine RK4h1(v,h,xf,tol,cant_ec) !Runge-Kutta con corrección de paso por método 1
real(8),dimension(0:cant_ec)::v
real::h,tol,xf
integer::cant_ec,i,n
real(8),dimension(0:cant_ec)::v1,v2
real(8)::error
n = int((xf-v(0))/h +0.5)
open(2,file = "derivada.txt",status="replace")
error = 2*tol
do i = 1,n, 1
do while(error > tol)
v1 = RK4(v,h,cant_ec)
v2 = RK4(v,h/2,cant_ec)
v2 = v2 + RK4(v+v2,h/2,cant_ec)
error = MAXVAL(ABS(v1-v2))
if (error > tol) then
h = h/2
end if
end do
end do
write(*,*)v1
write(2,*)v1
close(2,status="keep")
call system("gnuplot -persist 'derivada.p'")
end subroutine Rk4h1
其中,h
是步长,v
是与ODE顺序相对应的cant_ec
分量向量(即:v(0)=x
,v(1)=y
,v(2)=y'
等),tol
是误差容差,xf
是x间隔的终点(假设它从0开始)。所有这些值都是在子程序调用之前由用户输入的。此特定函数的初始值为y(0)=-1
。其他所有内容都由用户在运行脚本时定义。
微分方程由下式给出:
function vprima(v,x,y) !definición de la función derivada
real(8),dimension(0:cant_ec)::v,vprima
vprima(0) = 1.0
vprima(1) = (-v(1)/(v(0)**2+1))
end function vprima
注意,在主程序上,此任务发生:
v(0) = x
v(1) = y
其中,x
和y
是用户给出的函数初始值
我的问题是,当我调用RK4h1时,脚本似乎陷入无限循环
任何帮助或线索都将不胜感激。谢谢。v2=v2+RK4(v+v2,h/2,cant_ec)
是错误的,应该是v2=RK4(v2,h/2,cant_ec)
,因为RK4
的结果是下一点,而不是下一点的更新。由于误差计算是错误的,因此步长会无限减小。大约减少50次后,RK4步骤将不再推进状态,增量太小
如果你有一个固定的步数和一个可变的步长,这将导致问题
内部循环没有任何意义。总体效果是,每次步长减小后,
i
都会增加1。所以理论上,如果nw我们需要一个完整的程序;否则,我们只是猜测。例如,我最初的猜测是您请求的容差太小。我没有添加完整的程序,因为这几乎就是它(至少在这个问题上,文件的其余部分是其他方法的声明,如Euler和Runge-Kutta-Fuhlberg)。尽管如此,我还是在问题中添加了一些关于初始值的详细信息,我现在意识到这一点很重要。希望其他人添加缺少的主程序并猜测导致问题的确切值集是获得帮助的一个相当好的方法。祝你好运,请看。关键是让其他人能够轻松地尝试您的代码,而无需进行不必要的工作。另外,请注意,real(8)
很难看,而且我理解它是不可移植的。我会相应地编辑这篇文章。谢谢你的更正。你能扩展一下“那么理论上,如果是nYes,时间循环应该是do while(v(0))谢谢。另外一个问题,什么会被认为是“太小了?”“局部误差?是否存在下限?由于第4阶,如果步长随因子2变化,单位步长误差随因子16变化。因此,建议上限和下限之间的间隙为20或50。或者,对于相应较小的步长因子,使用较窄的间隙。