Fortran subroutine returning wrong values

此生再无相见时 提交于 2019-12-28 03:12:15

问题


Hey I'm working on a fortran program and have ran across an odd problem. When I try to output some values of an array directly before calling a specific subroutine I get the correct values. I then try to output some values of the same array right as I start the subroutine, and they are 0. I finally output the values of the array after the subroutine and the values are back to the expected values. Could anyone help me understand why? My code is below:

First, the calling of the subroutine in the main function, with values I want outputted in the write statements:

if (iter .eq. 5) then
  write(*,*) 'vp vals: ',vp(0,23471), vp(0,23475)
end if 

CALL GRID_DIVISION( &
&            NPTMAX, DIM, TYPEMAX, NEIGHMAX, NPTC, GRIDLIMIT, &
&            GRIDN, GRIDNUM, GRID, GNEIGH, XP, PTTYPE, TYPE, &
&            GRIDP, TEMP_GRIDP, GNEIGHMAX, PAINT, VP, ITER, gridvel &
&          )

if (iter .eq. 5) then
  write(*,*) 'vp vals: ',vp(0,23471), vp(0,23475)
end if 

This is calling the following subroutine, of which I will post only the relevant part:

SUBROUTINE GRID_DIVISION( &
&            NPTMAX, DIM, TYPEMAX, NEIGHMAX, NPTC, GRIDLIMIT, &
&            GRIDN, GRIDNUM, GRID, GNEIGH, XP, PTTYPE, TYPE, &
&            GRIDP, TEMP_GRIDP, GNEIGHMAX, PAINT,VP,ITER, gridvel &
&          )
  IMPLICIT NONE
  INTEGER, INTENT(IN)    :: NPTMAX, DIM, TYPEMAX, NEIGHMAX, GNEIGHMAX
  INTEGER, INTENT(IN)    :: NPTC
  INTEGER, INTENT(IN)    :: GRIDLIMIT
  INTEGER, INTENT(IN)    :: GRIDN(0: DIM - 1)
  INTEGER, INTENT(IN)    :: GRIDNUM
  INTEGER, INTENT(IN)    :: PTTYPE(0: NPTMAX)
  INTEGER, INTENT(IN)    :: TYPE(0: TYPEMAX)
  INTEGER, INTENT(INOUT) :: GRIDP(0: NPTMAX)
  INTEGER, INTENT(INOUT) :: GNEIGH(1: GRIDLIMIT, 0: GNEIGHMAX)
  REAL   , INTENT(IN)    :: GRID(1: GRIDLIMIT, 0: DIM - 1, 0: 1)
  REAL   , INTENT(IN)    :: XP(0: DIM - 1, 0: NPTMAX)
  REAL   , INTENT(IN)    :: VP(0: DIM - 1, 0: NPTMAX)
  INTEGER, INTENT(INOUT) :: TEMP_GRIDP(0: NPTMAX)
  INTEGER, INTENT(INOUT) :: PAINT(0:NPTMAX)
  INTEGER, INTENT(INOUT) :: ITER
  real, intent(inout)    :: gridvel(GRIDNUM,0:1)
  INTEGER :: II, JJ, KK
  INTEGER :: DNUM
  INTEGER :: GRIDXP
  INTEGER :: SGRIDXP
  INTEGER :: EGRIDXP
  INTEGER :: SGRIDYP
  INTEGER :: EGRIDYP
  INTEGER :: SEARCH
  INTEGER :: SCOUNT
  INTEGER :: FCOUNT
  INTEGER :: ERROR
  INTEGER, PARAMETER :: CELL = 2 

  if (iter .eq. 5) then
    write(*,*) 'vp vals: ',vp(0,23471), vp(0,23475)
  end if 
...
end subroutine

With more stuff after this section which is not ouputted. When I run the code my outputs on iteration 5 for this section are:

vp vals:    75.00000        75.00000
vp vals:     0.00000000E+00  0.0000000E+00
vp vals:    75.00000        75.00000

I simply can't figure out why my array VP does not have values in the subroutine.


回答1:


Manually, setting explicit-shape arrays a(0:N-1,0:M) is extremely error prone. I suggest using assumed-shape arrays a(:,:) to pass arguments. Also, when you pass arrays as arguments to subroutines, the upper and lower bounds of the actual argument are not maintained in the call unless the lower bound is 1. However, when passing pointers, the lower and upper bounds are maintained. For instance,

program main

  use, intrinsic :: iso_fortran_env, only: &
       stdout => OUTPUT_UNIT, &
       compiler_version, &
       compiler_options

  ! Explicit typing only
  implicit none

  real               :: foo(10,10)
  real, target       :: bar(0:9,0:9)
  real, pointer      :: ptr(:,:) => null()

  call peek_assumed_shape(foo, 'peek_assumed_shape: foo(10,10)')
  call peek_assumed_shape(bar, 'peek_assumed_shape: bar(0:9,0:9)')

  ptr => bar
  call peek_pointer(ptr, 'peek_pointer: ptr => bar')

  ptr(42:,42:) => bar
  call peek_pointer(ptr, 'peek_pointer: ptr(42:,42:) => bar')

  nullify( ptr )

  write (stdout, '(/4a/)') &
       'This file was compiled using compiler version ', compiler_version(), &
       ' and compiler options ', compiler_options()

contains


  subroutine peek_assumed_shape(array, description)
    ! Calling arguments
    real,              intent (in) :: array(:,:)
    character (len=*), intent (in) :: description

    write (stdout, '(/a)') description
    write (stdout, *) 'dim=1 ', lbound(array, dim=1), ubound(array,dim=1)
    write (stdout, *) 'dim=2 ', lbound(array, dim=2), ubound(array,dim=2)


  end subroutine peek_assumed_shape

  subroutine peek_pointer(array, description)
    ! Calling arguments
    real, pointer,     intent (in) :: array(:,:)
    character (len=*), intent (in) :: description

    if (associated(array)) then
       write (stdout, '(/a)')  description
       write (stdout, *) 'dim=1 ', lbound(array, dim=1), ubound(array,dim=1)
       write (stdout, *) 'dim=2 ', lbound(array, dim=2), ubound(array,dim=2)
    end if

  end subroutine peek_pointer

end program main

returns the following

peek_assumed_shape: foo(10,10)
 dim=1            1          10
 dim=2            1          10

peek_assumed_shape: bar(0:9,0:9)
 dim=1            1          10
 dim=2            1          10

peek_pointer: ptr => bar
 dim=1            0           9
 dim=2            0           9

peek_pointer: ptr(42:,42:) => bar
 dim=1           42          51
 dim=2           42          51

This file was compiled using compiler version GCC version 5.4.0 20160609 and compiler options -mtune=generic -march=x86-64 -O3 -Wall -std=f2008ts



回答2:


I figured it out. VP was allocated as

VP(0:DIM,0:NPTMAX) 

in the main program and

VP(0:DIM-1,0:NPTMAX) 

in the subroutine! This caused the error.



来源:https://stackoverflow.com/questions/38140951/fortran-subroutine-returning-wrong-values

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!