passar array alocado da sub-rotina para o programa principal em fortran; usar ou módulo? interface?
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
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 subs
com procedimento de módulo makef
; uma sub-rotina externa makef
.
O programa principal usa o módulo subs
e 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 f
que 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.
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.