Функция Fortran, возвращающая неверные значения

Эй, я работаю над программой на Фортране и столкнулся со странной проблемой. Когда я пытаюсь вывести некоторые значения массива непосредственно перед вызовом определенной подпрограммы, я получаю правильные значения. Затем я пытаюсь вывести некоторые значения из того же массива сразу же после запуска подпрограммы, и они равны 0. Я наконец выводю значения массива после подпрограммы, и значения возвращаются к ожидаемым значениям. Может ли кто-нибудь помочь мне понять, почему? Мой код ниже:

Во-первых, вызов подпрограммы в главной функции со значениями, которые я хочу вывести в операторах записи:

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 

Это вызывает следующую подпрограмму, из которой я опубликую только соответствующую часть:

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

С большим количеством материала после этого раздела, который не выводится. Когда я запускаю код, мои выводы на итерации 5 для этого раздела:

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

Я просто не могу понять, почему мой массив VP не имеет значений в подпрограмме.

2 ответа

Решение

Я понял. VP был выделен как

VP(0:DIM,0:NPTMAX) 

в основной программе и

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

в подпрограмме! Это вызвало ошибку.

Ручная установка массивов явной формы a(0:N-1,0:M) чрезвычайно подвержен ошибкам. Я предлагаю использовать массивы предполагаемой формы a(:,:) передать аргументы. Кроме того, когда вы передаете массивы в качестве аргументов подпрограммам, верхняя и нижняя границы фактического аргумента не поддерживаются в вызове, если только нижняя граница не равна 1. Однако при передаче указателей нижняя и верхняя границы сохраняются. Например,

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

возвращает следующее

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
Другие вопросы по тегам