我有一个 Fortran 脚本,它从内部模块调用多个子例程(见下文)。
子程序按顺序调用。
我注意到前两个调用正常执行,但最后一个子例程没有执行。
我尝试将子例程转换为函数,但遇到了同样的问题。
非常感谢有关如何解决此问题的想法。
module tmod
contains
subroutine readata(fname,tm,hd,td,nrec)
! read input data and returns arrays
implicit none
integer :: io,i
integer,intent(in) :: nrec
character(len=40) :: fname
real(kind=8),allocatable,intent(out) :: tm(:),hd(:),td(:)
allocate(tm(nrec-1))
allocate(hd(nrec-1))
allocate(td(nrec-1))
open(10,file=fname,status='old',action='read')
read(10,*)
do i=1,nrec-1
read(10,*) tm(i),hd(i),td(i)
end do
close(10)
return
end subroutine readata
subroutine fd(nrec,t_arr,v_arr,derv_arr)
implicit none
integer,intent(in) :: nrec
integer :: i
real(kind=8),allocatable,intent(out) :: derv_arr(:)
real(kind=8),dimension(:),intent(in) :: t_arr, v_arr
allocate(derv_arr(nrec-2))
do i=2,nrec-1
derv_arr(i)= (v_arr(i+1)-v_arr(i-1))/(t_arr(i+1)-t_arr(i-1))
end do
return
end subroutine fd
subroutine sd(nrec,t_arr,v_arr,derv2_arr)
implicit none
integer,intent(in) :: nrec
integer :: i
real(kind=8),dimension(:),intent(in) :: t_arr,v_arr
real(kind=8),allocatable,intent(out) :: derv2_arr(:)
allocate(derv2_arr(nrec-2))
do i=2,nrec-1
derv2_arr(i)=(v_arr(i+1)-2*v_arr(i)+v_arr(i-1))
end do
return
end subroutine sd
end module tmod
program main
use tmod
implicit none
character(len=40) :: filename
real(kind=8),allocatable :: tg(:), hg(:), tig(:),pd2(:), sed(:), pd1(:)
integer :: nrg
! input parameters
filename="test_data.dat"
nrg=5
! calling subroutines
call readata(filename, tg, hg, tig, nrg)
write(*,*) hg
call fd(nrg,tg,tig,sed)
write(*,*) "First"
write(*,*) sed
call fd(nrg,tg,hg,pd1)
write(*,*) "First 1"
write(*,*) pd1
call sd(nrg,tg,hg,pd2)
write(*,*) "Second"
write(*,*) pd2
end program maintype
以下是输入文件“test_data.dat”的内容
t h ti
0 12.113 1.1e-3
15 12.123 1.12e-3
30 12.156 1.11e-3
45 12.134 1.15e-3
如果您在编译应用程序时启用了数组边界检查,您会很快发现问题:
$ gfortran -O2 -fcheck=all -g callbug.f90
$ ./a.out
12.113000000000000 12.122999999999999 12.156000000000001 12.134000000000000
At line 36 of file callbug.f90
Fortran runtime error: Index '5' of dimension 1 of array 'v_arr' above upper bound of 4
您的根本问题似乎是子例程中的
nrec
变量不是您拥有的记录数,而是数据文件中的行数。由于文件中的标题行,实际记录数减少了 1,但由于您在循环体中使用 i+1
索引,因此必须在 nrec-2
处停止迭代。除了启用边界检查之外,避免此类很容易犯的错误的一种方法是使用 Fortran size 内在函数来获取要迭代的数组的大小,而不是使用单独的 nrec
变量。例如,在程序中的第 35 行和第 51 行,而不是
do i=2,nrec-1
写为
do i=2,size(v_arr)-1