Fortran 子例程的顺序调用问题

问题描述 投票:0回答:1

我有一个 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
fortran subroutine
1个回答
0
投票

如果您在编译应用程序时启用了数组边界检查,您会很快发现问题:

$ 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
© www.soinside.com 2019 - 2024. All rights reserved.