问题
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