pasar la matriz asignada de la subrutina al programa principal en fortran; uso o módulo? ¿interfaz?

Aug 16 2020

Quiero asignar una matriz en una subrutina y luego usar esta matriz en el programa principal y pasarla a otra subrutina. En el pasado (¿F77?) El paso se podía hacer en un bloque común, pero hoy en día el procedimiento preferido parece ser utilizar un módulo. Cuando intento esto, como en el ejemplo de código, el compilador me dice

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

Aparentemente, el programa principal piensa que 'f' es un escalar: pero leí este código para significar que lo he declarado como una matriz unidimensional, tanto dentro de la subrutina como en el programa principal. ¿Qué me estoy perdiendo?

Probé variaciones, como declarar las variables como parte del módulo, pero nada en lo que pudiera pensar hizo que la compilación estuviera libre de errores (y algunas produjeron muchos más errores ;-(). Cualquier información es muy apreciada.

          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

Respuestas

2 francescalus Aug 16 2020 at 17:19

Los módulos en Fortran no son como archivos de encabezado en otros lenguajes que simplemente proporcionan información sobre cosas definidas en otro lugar. Existe el concepto de "definición diferida" (submódulos) pero en este caso el módulo debe decir todo sobre la subrutina, no simplemente intentar señalar su existencia.

En el ejemplo de la pregunta, tenemos: el programa principal; un módulo subscon procedimiento de módulo makef; una subrutina externa makef.

El programa principal utiliza el módulo subsy su procedimiento makef, por lo que en el programa principal se hace referencia makefal procedimiento del módulo, no a la subrutina externa makef.

La subrutina del módulo makeftiene el argumento fque no tiene declaraciones de declaración, por lo que es una función escalar / externa declarada implícitamente. Este es el mensaje del compilador. Úselo implicit noneen módulos, tal como está en el programa principal y en la subrutina externa aquí.

La definición completa de la subrutina debe colocarse en el 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, si uno quiere referirse a la implementación posterior de un procedimiento externo, un bloque de interfaz puede aparecer en el módulo sin declarar la subrutina en sí. En este caso, aún será necesario especificar la interfaz 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

En este caso, no prefiera el bloque de interfaz.

VladimirF Aug 16 2020 at 13:07

Solo colocó la copia de la primera y la última línea en el módulo. Eso no puede funcionar. Debe mover toda la subrutina al módulo.