passar array alocado da sub-rotina para o programa principal em fortran; usar ou módulo? interface?

Aug 16 2020

Quero alocar uma matriz em uma sub-rotina e, em seguida, usar essa matriz no programa principal e passá-la para alguma outra sub-rotina. Antigamente (F77?) A passagem podia ser feita em um bloco comum, mas hoje em dia o procedimento preferido parece ser usar um módulo. Quando tento fazer isso, como no exemplo de código, o compilador me diz

Rank mismatch in argument ‘f’ at (1) (scalar and rank-1)

Aparentemente, o programa principal pensa que 'f' é um escalar: mas, eu li esse código para significar que eu o declarei como um array unidimensional, tanto dentro da sub-rotina quanto no programa principal. o que estou perdendo?

Eu tentei variações, como declarar as variáveis ​​como parte do módulo, mas nada que eu pudesse pensar tornou a compilação livre de erros (e alguns produziram muitos mais erros ;-(). Qualquer insight é muito apreciado.

          module subs
        contains
        subroutine makef(f)
        end subroutine makef
      end module subs
c-----------------------------------------------------------------------
      program work

      use subs
      implicit none
        real, allocatable :: f(:)

      call makef(f)

      write (*,*) f
      stop
      end
c---------------------------------------------------------------------
      subroutine makef(f)
      implicit none

      real, allocatable, intent(out) :: f(:)
      integer :: i
      integer :: is

      is=10
      allocate(f(-is:is))

      do i=-is,is
        f(i)=i
      end do
      return
      end subroutine makef

Respostas

2 francescalus Aug 16 2020 at 17:19

Módulos em Fortran não são como arquivos de cabeçalho em outras linguagens que simplesmente fornecem informações sobre coisas definidas em outro lugar. Existe o conceito de "definição diferida" (submódulos), mas, neste caso, o módulo deve dizer tudo sobre a sub-rotina, não simplesmente tentar apontar para sua existência.

No exemplo da pergunta, temos: o programa principal; um módulo subscom procedimento de módulo makef; uma sub-rotina externa makef.

O programa principal usa o módulo subse seu procedimento makef, portanto, a referência no programa principal makefé para esse procedimento de módulo e não para a sub-rotina externa makef.

A sub makef- rotina do módulo possui o argumento fque não possui instruções de declaração, tornando-a uma função escalar / externa declarada implicitamente. Esta é a mensagem do compilador. Use implicit noneem módulos, assim como no programa principal e na sub-rotina externa aqui.

Toda a definição da sub-rotina deve ser colocada no módulo:

module subs
  implicit none
contains
  subroutine makef(f)
    real, allocatable, intent(out) :: f(:)
    integer :: i
    integer :: is

    is=10
    allocate(f(-is:is))

    do i=-is,is
      f(i)=i
    end do
  end subroutine makef
end module subs

Alternativamente, se alguém quiser se referir à implementação posterior de um procedimento externo, um bloco de interface pode ser apresentado no módulo sem declarar a própria sub-rotina. Neste caso ainda será necessário especificar a interface completa:

module subs
  implicit none

! An interface block to give an explicit interface to the external subroutine makef
  interface
     subroutine makef(f)
       implicit none
       real, allocatable, intent(out) :: f(:)
     end subroutine makef
  end interface
end module subs

Nesse caso, não dê preferência ao bloco de interface.

VladimirF Aug 16 2020 at 13:07

Você apenas colocou a cópia da primeira e da última linha no módulo. Isso não pode funcionar. Você deve mover toda a sub-rotina para o módulo.