我几个月来一直在FORTRAN 77中遇到分段故障问题,我真的无法弄清楚我错在哪里。我是Fortran的新手。
我正在编写一个程序(main
),我在其中调用子程序(source
)。该子程序执行4阶Runge-Kutta方法(由Press,Teukolsky,Vetterling,Flannery在 Numerical Recipes in Fortran 77 中提出)来求解微分方程并从瞬间推进某些输入数据值到下一个。
为了执行Runge-Kutta方法,在source
中调用另一个子例程deriv
,它在数值上计算微分方程中的导数。对于Runge-Kutta方法,子例程deriv
必须被调用四次,我必须在x和y两个方向上执行数据值:因此,全局地,deriv
被调用八次source
。
通过Runge-Kutta前进的值被收集到最大大小mxnn=200000
的矢量(param.fi
中包含的参数),但在程序的过程中只有一部分(大小) nodes
)将被填补并且如此先进。这些向量传递给source
,它们的组件传递给deriv
以获得Runge-Kutta方法。
这是main
的摘录(这是一个非常重要的节目,因此我已经删除了我认为不必要的内容):
PROGRAM main
INCLUDE 'param.fi'
INTEGER nodes
DOUBLEPRECISION z0
DOUBLEPRECISION deltaxnp1(mxnn),zxnp1(mxnn),u0xnp1(mxnn)
DOUBLEPRECISION deltaynp1(mxnn),zynp1(mxnn),u0ynp1(mxnn)
DOUBLEPRECISION deltaxn(mxnn),zxn(mxnn),u0xn(mxnn)
DOUBLEPRECISION deltayn(mxnn),zyn(mxnn),u0yn(mxnn)
...
...
CALL source(nodes,
+ z0,deltaxn,u0xnp1,u0xn,zxn,zxnp1,deltaxnp1,
+ deltayn,u0ynp1,u0yn,zyn,zynp1,deltaynp1,
+ [...])
...
...
END program main
这是我在不同模块中编写的子程序source
:
SUBROUTINE source(nodes,
+ z0,deltaxin,u0xnew,u0xin,zx,zxout,deltaxout,
+ deltayin,u0ynew,u0yin,zy,zyout,deltayout,
+ [...])
INTEGER nodes, i
DOUBLEPRECISION z0
DOUBLEPRECISION deltaxin(*),u0xnew(*),u0xin(*)
DOUBLEPRECISION zx(*), zxout(*),deltaxout(*)
DOUBLEPRECISION deltayin(*),u0ynew(*)
DOUBLEPRECISION u0yin(*),zy(*),zyout(*),deltayout(*)
DOUBLEPRECISION duxdt(mxnn),duydt(mxnn)
*** Variables needed for Runge-Kutta ***
DOUBLEPRECISION dtmezzo,d6,th
DOUBLEPRECISION dzini(mxnn),dzt(mxnn),dzm(mxnn)
DOUBLEPRECISION zt(mxnn)
DO i=1,nodes
...
dtmezzo=dt*0.5D0
d6=dt/6.D0
th = time + dtmezzo
*** Runge-Kutta for values in x direction
*** INPUT: zx(i)
*** OUTPUT: zxout(i)
CALL deriv(zx(i),u0xnew(i),z0,duxdt(i),dzini(i))
zt(i)=zx(i)+dtmezzo*dzini(i)
CALL deriv(zt(i),u0xnew(i),z0,duxdt(i),dzt(i))
zt(i)=zx(i)+dtmezzo*dzt(i)
CALL deriv(zt(i),u0xnew(i),z0,duxdt(i),dzm(i))
zt(i)=zx(i)+dt*dzm(i)
dzm(i)=dzt(i)+dzm(i)
CALL deriv(zt(i),u0xnew(i),z0,duxdt(i),dzt(i))
zxout(i)=zx(i)+t6*(dzini(i)+dzt(i)+2.*dzm(i))
*** Runge-Kutta for values in y direction
*** INPUT: zy(i)
*** OUTPUT: zyout(i)
CALL deriv(zy(i),u0ynew(i),z0,duydt(i),dzini(i)) !!!!!
zt(i)=zy(i)+dtmezzo*dzyini(i)
CALL deriv(zt(i),u0ynew(i),z0,duydt(i),dzt(i))
zt(i)=zy(i)+dtmezzo*dzyt(i)
CALL deriv(zt(i),u0ynew(i),z0,duydt(i),dzm(i))
zt(i)=zy(i)+dt*dzm(i)
dzm(i)=dzt(i)+dzm(i)
CALL deriv(zt(i),u0ynew(i),z0,duydt(i),dzt(i))
zyout(i)=zy(i)+t6*(dzini(i)+dzt(i)+2.*dzm(i))
...
ENDDO
RETURN
END
这是子程序deriv
:
SUBROUTINE deriv(Z,u0,z0,dudt,der)
DOUBLEPRECISION Z,u0,z0,dudt,der
der = ( (((0.4D0**2)*u0)/z0) - Z*(dexp(Z)-Z-1)
+ * (dudt/u0) ) / ( dexp(Z)*(Z-1)+1 )
END
在编译程序时(使用GNUfortran),它没有给我带来任何问题:但是在运行程序后出现Segmentation fault (core dumped)
错误并且程序中止。经过一些分析后,似乎问题在于我第一次为y方向的值调用deriv
(即第五次调用,我在代码中用!!!!!
标记)。
对我来说很奇怪,因为如果我尝试编译并运行程序而没有 y方向块(仅针对x方向解决Runge-Kutta)一切都很顺利。 deriv
的形式在两个方向上完全相同:只有输入和输出发生变化。
我检查了数组维度,似乎没有任何错误(至少对我来说),我担心我的脚本中存在概念错误。我在Stack Overflow上找到了各种答案,但无济于事。
我考虑使用dbg
和-g
标志进行调试,但该程序是通过makefile编写的,我无法找到如何使用该标志。