Функция Fortran PRESENT() с предполагаемым массивом длины дает сбой EDITED

я полностью потерян.

Я пытаюсь передать функции в фортране два необязательных аргумента, и эти два являются массивами неизвестной длины. Код компилируется нормально, но когда программа запускается, происходит сбой во время вычисления функции PRESENT(arg). В командной строке нет сообщения об ошибке, вместо этого появляется только уведомление об ошибке Windows и сообщает мне, что «main.exe перестал работать». Есть идеи, как это решить?

Вот код, удалил все что не нужно.

MODULE types
  ! Underlying data types: Bra, Ket, and Oper
  type bra
    complex*8, dimension(:,:), allocatable  :: dat
    integer*4                               :: typ ! = "Bra"
    integer*4, dimension(2)                 :: dims
  end type bra

  type ket
    complex*8, dimension(:,:), allocatable  :: dat
    integer*4                               :: typ ! = "Ket"
    integer*4, dimension(2)                 :: dims
  end type ket

  type oper
    complex*8, dimension(:,:), allocatable  :: dat
    integer*4                               :: typ ! = "Operator"
    integer*4, dimension(2)                 :: dims
  end type oper
END MODULE types

MODULE basics
  ! The types are declared in an extra module, to be imported here
  ! Otherwise it is not possible to use derived types in procedures
  use types

  interface operator (*)
    ! "Quantum" multiplication
    procedure otk ! Operator  Times Ket         O  *|B > = |C>
  end interface

  CONTAINS
  ! Fock state
  function fock(N,M)
    ! N is the dimension of the underlying array
    ! M is the number of photons inside
    ! M=1 is vacuum
    integer*4 :: N,M
    type(ket) :: fock

    ! Check is the passed dimensions are okay
    if (N<2 .or. M<0 .or. M > N-1) then
      print*,'Invalid input while making a fock state'
      print*,'N=',N,'M=',M
      stop
    end if

    ! Allocate and initilaize with zeros
    allocate(fock%dat(N,1))
    fock%dat = (0d0,0d0)

    ! Now actually make the state by replacing a zero with 1
    fock%dat(M+1,1) = (1d0,0d0)

    ! Set type of the object to 'ket'
    fock%typ = 2

    ! Set the dimensions
    fock%dims = [N,1]
  end function fock

  ! Identity matrix
  function qeye(N)
    integer*4   :: N,i
    type(oper)  :: qeye

    ! Allocate and initilaize with zeros
    allocate(qeye%dat(N,N))
    qeye%dat = (0d0,0d0)

    ! Set diagonal elements to 1
    do i = 1,N
      qeye%dat(i,i) = (1d0,0d0)
    end do

    ! Set type of the object to 'oper'
    qeye%typ = 4

    ! Set the dimensions
    qeye%dims = [N,N]
  end function qeye

  ! Operator Times Ket
  function otk(left, right)
    type(oper), intent(in)  :: left
    type(ket), intent(in)   :: right
    type(ket)               :: otk
    ! If the operator is as wide, as the state is high, do matrix multiplication
    if (left%dims(2) == right%dims(1)) then
      ! Result is a Ket vector again
      allocate(otk%dat(left%dims(1),1))
      otk%dat = matmul(left%dat,right%dat)
      ! Also set data type and dimensions of the result
      otk%dims = [right%dims(1),1]
      otk%typ = 2
      return
    else
      print*,'You are trying to use an operator on a ket of inconsistent dimensions'
      print*,left%dims,'and',right%dims
      stop
    end if
  end function otk
end module basics

MODULE RK
  ! Import modules to work with quantum objects
  use types
  use basics

  contains
  subroutine rungekutta(state,HAM,times,results)
    ! In-/Output:
    ! Starting state, also final state
    type(ket)             :: state 
    ! Function delivering time dependent hamiltonian
    type(oper), external  :: HAM 
    ! Array with times at which to do calculations
    real*8, dimension(:)  :: times
    ! Placeholder for the length of a given time step
    real*8                :: t_0, t_step
    ! Optional array of ket states to hold all the intermediate results
    type(ket), dimension(:),optional  :: results 

    ! Variables for internal calculations
    type(ket) :: psi0

    ! Looping coefficients
    integer*8 :: ii
    ! Start of the calculations
    ! (The actual Runge-Kutta method is different, but not needed now)
    results(1) = state
    do ii = 1, size(times)-1
      t_0     = times(ii)
      t_step  = times(ii+1) - times(ii)

      psi0    = results(ii)
      results(ii+1) = HAM(t_0) * psi0   
    end do

    ! Save the last calculated state to the input/output variable
    state = results(size(results)) 
  end subroutine rungekutta
end MODULE RK

module dummy
  ! Import modules to work with quantum objects
  use types
  use basics

  CONTAINS
  ! Define Hamiltonian function

  function testHAM(t, freqs, coefs)
    type(oper)  :: testHAM
    real*8      :: t

    ! Optional variables is the Hamiltonian is time dependent
    real*8, dimension(:), optional  :: freqs, coefs

    testHAM = qeye(2)
    ! Variable part
    if (.NOT.present(freqs)) then
      print*,'gotcha'
    end if
  end function testHAM
end module dummy

program main
  ! Import modules to work with quantum objects
  use types
  use basics
  use RK

  ! Import hamilton definition
  use dummy

  IMPLICIT NONE

  ! Define variables
  type(ket)              :: start, goal
  real*8, dimension(:), allocatable  :: timesarr
  integer*4              :: N,i,M,j,k,l,mm
  type(ket), dimension(:), allocatable  :: results

  ! Set number of steps, and the total time
  N = 5000
  allocate(timesarr(N))
  timesarr = [0d0,1d0]

  start=fock(2,0)

  ! Allocate the vector holding the results
  allocate(results(N))
  results = start

  call rungekutta(start,testHAM,timesarr,results)
end program main

Я использую необязательное ключевое слово также с массивом «результаты» и где-то еще, и все работает нормально. Я был бы очень признателен за любую помощь, потому что я действительно не в настроении заниматься этим, потому что это сделало бы код еще более грязным :)

Заранее спасибо!


person Maxim Moloshenko    schedule 23.10.2013    source источник
comment
Основная программа на самом деле предназначена только для того, чтобы показать вам, как я передаю аргументы, или, на самом деле, не передаю. Я почти уверен, что проблема где-то в функции.   -  person Maxim Moloshenko    schedule 23.10.2013
comment
Я не думаю, что кто-то сможет вам помочь, потому что вы не указали types, basic и RK выше. Вы понимаете идею минимального рабочего примера?   -  person Kyle Kanos    schedule 23.10.2013
comment
Вы также не указали фактическую ошибку, которую вы получаете. Обновите как компилируемый пример, который вызывает ошибку, и связанную с ней ошибку.   -  person Kyle Kanos    schedule 23.10.2013
comment
Хорошо, сейчас сделаю. Я просто надеялся, что, может быть, я проглядел что-то простое в синтаксисе, и кто-то заметит такую ​​​​ошибку   -  person Maxim Moloshenko    schedule 23.10.2013
comment
Это может занять некоторое время, извините!   -  person Maxim Moloshenko    schedule 23.10.2013
comment
Фоновые функции теперь находятся в начале кода, основное — в самом конце.   -  person Maxim Moloshenko    schedule 23.10.2013
comment
Я вырезал и вставил ваш код, он компилируется и выполняется без ошибок. Я использую Intel 14.0.0.103 под VS2010 на 64-битной установке Windows 7.   -  person High Performance Mark    schedule 23.10.2013
comment
Вопрос: теперь, когда вы сократили свой код до самого необходимого, он по-прежнему выдает ту же ошибку? (Я спрашиваю из-за комментария @HighPerformanceMark.)   -  person dmm    schedule 23.10.2013
comment
Он скомпилировался и запустился без ошибок с помощью gfortran на Mac. Он не производит никакого вывода, поэтому трудно понять, правильно ли он работает.   -  person M. S. B.    schedule 24.10.2013
comment
Я попробовал это сейчас также с ifort, и он отлично скомпилировался и работал, когда я заменил процедуру процедурой модуля. Почему gfortran все еще создает .exe, который падает, я понятия не имею, но это нормально. Спасибо за вашу помощь!!!   -  person Maxim Moloshenko    schedule 24.10.2013
comment
gfortran дает сбой, потому что в вашем коде есть ошибка!   -  person IanH    schedule 25.10.2013


Ответы (2)


Для процедуры с необязательными аргументами требуется явный интерфейс, чтобы процедура была доступна в любой области, где на процедуру ссылаются.

Представленный код не соответствует этому требованию.

Обратите внимание, что процедура упоминается дважды.

В порядке выполнения первая ссылка — когда процедура testHAM связана с фиктивным аргументом HAM при вызове rungekutta в основной программе — в порядке — доступен явный интерфейс (идентификатор для процедуры модуля — поэтому явный интерфейс автоматический).

А вот вторая ссылка в порядке выполнения — при вызове фиктивной процедуры HAM — не годится. Фиктивный аргумент объявляется «только» с использованием оператора объявления типа с внешним атрибутом. Это не дает процедуре явного интерфейса.

(С языком как есть - мое мнение таково, что если вам нужно (или даже просто «должно») использовать внешний атрибут, то ваш код демонстрирует плохой стиль.)

Правильный непосредственный подход состоит в том, чтобы использовать один из методов предоставления аргументу фиктивной процедуры явного интерфейса - возможно, через интерфейсный блок или оператор объявления процедуры со спецификацией proc-interface.

Если желаемые релевантные характеристики интерфейса фиктивной процедуры не соответствуют фактическому интерфейсу процедуры testHAM (здесь предполагается, что процедура rungekutta не заботится или не хочет знать о необязательных аргументах), тогда вам может понадобиться использовать процедуру-оболочку или аналогичный подход для пересылки вызова процедуры.

Изменить, чтобы добавить: хотя стандарт не требует этого, было бы разумно ожидать предупреждения от компилятора для такого использования. Хотя ассоциация процедуры с необязательными аргументами с фиктивной процедурой с неявным интерфейсом является «законной», в этом случае фиктивная процедура в любом случае не может быть использована. Возможно, стоит обсудить это с поставщиком вашего процессора Fortran.

person IanH    schedule 24.10.2013

lanH конечно прав. Явное решение выглядит так:

MODULE types
  ! Underlying data types: Bra, Ket, and Oper
  type bra
    complex*8, dimension(:,:), allocatable  :: dat
    integer*4                               :: typ ! = "Bra"
    integer*4, dimension(2)                 :: dims
  end type bra

  type ket
    complex*8, dimension(:,:), allocatable  :: dat
    integer*4                               :: typ ! = "Ket"
    integer*4, dimension(2)                 :: dims
  end type ket

  type oper
    complex*8, dimension(:,:), allocatable  :: dat
    integer*4                               :: typ ! = "Operator"
    integer*4, dimension(2)                 :: dims
  end type oper
END MODULE types

MODULE basics
  ! The types are declared in an extra module, to be imported here
  ! Otherwise it is not possible to use derived types in procedures
  use types

  interface operator (*)
    ! "Quantum" multiplication
    procedure otk ! Operator  Times Ket         O  *|B > = |C>
  end interface

  CONTAINS
  ! Fock state
  function fock(N,M)
    ! N is the dimension of the underlying array
    ! M is the number of photons inside
    ! M=1 is vacuum
    integer*4 :: N,M
    type(ket) :: fock

    ! Check is the passed dimensions are okay
    if (N<2 .or. M<0 .or. M > N-1) then
      print*,'Invalid input while making a fock state'
      print*,'N=',N,'M=',M
      stop
    end if

    ! Allocate and initilaize with zeros
    allocate(fock%dat(N,1))
    fock%dat = (0d0,0d0)

    ! Now actually make the state by replacing a zero with 1
    fock%dat(M+1,1) = (1d0,0d0)

    ! Set type of the object to 'ket'
    fock%typ = 2

    ! Set the dimensions
    fock%dims = [N,1]
  end function fock

  ! Identity matrix
  function qeye(N)
    integer*4   :: N,i
    type(oper)  :: qeye

    ! Allocate and initilaize with zeros
    allocate(qeye%dat(N,N))
    qeye%dat = (0d0,0d0)

    ! Set diagonal elements to 1
    do i = 1,N
      qeye%dat(i,i) = (1d0,0d0)
    end do

    ! Set type of the object to 'oper'
    qeye%typ = 4

    ! Set the dimensions
    qeye%dims = [N,N]
  end function qeye

  ! Operator Times Ket
  function otk(left, right)
    type(oper), intent(in)  :: left
    type(ket), intent(in)   :: right
    type(ket)               :: otk
    ! If the operator is as wide, as the state is high, do matrix multiplication
    if (left%dims(2) == right%dims(1)) then
      ! Result is a Ket vector again
      allocate(otk%dat(left%dims(1),1))
      otk%dat = matmul(left%dat,right%dat)
      ! Also set data type and dimensions of the result
      otk%dims = [right%dims(1),1]
      otk%typ = 2
      return
    else
      print*,'You are trying to use an operator on a ket of inconsistent dimensions'
      print*,left%dims,'and',right%dims
      stop
    end if
  end function otk
end module basics

MODULE RK
  ! Import modules to work with quantum objects
  use types
  use basics

  contains
  subroutine rungekutta(state,HAM,times,results)
    ! In-/Output:
    ! Starting state, also final state
    type(ket)             :: state 
    ! PeMa: Function delivering time dependent hamiltonian (now a correct interface)
    interface
    function HAM(t,freqs,coefs)
       use types
       ! type(oper),external :: HAM
       ! Edit (see comments) :
       type(oper) :: HAM
       real(8)      :: t
       real(8), dimension(:),allocatable,optional :: freqs, coefs
    end function
    end interface

    ! PeMa: define testing arrays to test the otional arguments:
    real(8), dimension(:),allocatable :: a, b

    ! Array with times at which to do calculations
    real*8, dimension(:)  :: times
    ! Placeholder for the length of a given time step
    real*8                :: t_0, t_step
    ! Optional array of ket states to hold all the intermediate results
    type(ket), dimension(:),optional  :: results 

    ! Variables for internal calculations
    type(ket) :: psi0

    ! Looping coefficients
    integer*8 :: ii
    ! Start of the calculations
    ! (The actual Runge-Kutta method is different, but not needed now)

    !PeMa: my testing arrays
    allocate(a(1:2))
    allocate(b(1:2))
    a=(/1d0,3d0/)
    b=(/2d0,4d0/)

    results(1) = state
    do ii = 1, size(times)-1
      t_0     = times(ii)
      t_step  = times(ii+1) - times(ii)

      psi0    = results(ii)

      !PeMa: use one of the next to lines and you see in the output that it's working now:
      results(ii+1) = HAM(t_0,a,b) * psi0   
      !results(ii+1) = HAM(t_0) * psi0   
    end do

    ! Save the last calculated state to the input/output variable
    state = results(size(results)) 
  end subroutine rungekutta
end MODULE RK

module dummy
  ! Import modules to work with quantum objects
  use types
  use basics

  CONTAINS
  ! Define Hamiltonian function

  function testHAM(t, freqs, coefs)
    type(oper)  :: testHAM
    real*8      :: t

    ! PeMa: Optional variables is the Hamiltonian is time dependent (I'm using allocatable to be sure about the 'position labeling' ... sorry can't say it better)
    real*8, dimension(:), allocatable,optional  :: freqs, coefs

    testHAM = qeye(2)
    ! Variable part
    !PeMa: I inserted some 'else' to test both possibilities: 
    if (.NOT.present(freqs)) then
      print*,'gotcha'
    else
      print*,freqs,coefs
    end if
  end function testHAM
end module dummy

program main
  ! Import modules to work with quantum objects
  use types
  use basics
  use RK

  ! Import hamilton definition
  use dummy

  IMPLICIT NONE

  ! Define variables
  type(ket)              :: start, goal
  real*8, dimension(:), allocatable  :: timesarr
  integer*4              :: N,i,M,j,k,l,mm
  type(ket), dimension(:), allocatable  :: results

  ! Set number of steps, and the total time (PeMa: 5 is enough ;-) )
  N = 5
  allocate(timesarr(N))
  timesarr = [0d0,1d0]

  start=fock(2,0)

  ! Allocate the vector holding the results
  allocate(results(N))
  results = start

  call rungekutta(start,testHAM,timesarr,results)
end program main

(Надеюсь) все точки, где я что-то изменил, помечены «PeMa». Теперь он не только компилируется (вероятно, везде), но действительно делает то, что должен делать. Вы можете проверить это, вводя и выводя две строки с помощью различных вызовов функций в rungecutta. Надеюсь, я смог вам помочь! Лучший

person PeMa    schedule 24.10.2013
comment
Ваше тело интерфейса для фиктивного аргумента пытается применить внешний атрибут к имени функции. Я думаю, что это ограничение или нарушение области действия, и его не следует компилировать. - person IanH; 25.10.2013
comment
Правильно, спасибо! Он компилируется и работает правильно с ним и без него. Но все же вы правы, это остатки от копипаст и не имеет никакого смысла. Я удалю это. Кроме того, я думаю, что для определения переменных следует использовать f90 std (т.е. real(8) вместо real*8). Некоторые компиляторы могут иметь проблемы с fortran77. - person PeMa; 25.10.2013
comment
Строго говоря, real(8) не соответствует стандарту, поскольку идентификаторы типов не обязательны для стандартов, а текущие компиляторы действительно демонстрируют различия в их интерпретации. - person High Performance Mark; 25.10.2013
comment
@HighPerformanceMark Строго соответствует стандарту по синтаксису, но не указан по смыслу. - person IanH; 27.10.2013
comment
@IanH: ты еще строже, чем я. Спасибо за дисциплину. - person High Performance Mark; 29.10.2013