Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29336 Discussions

Allocatable output arrays in passing function

gtokic
Beginner
523 Views
Hi everybody,

I have a problem when passing an external function which has an array as an output argument. In its host module, the size of this array is defined. However, when I pass it as an argument to a procedure in a different module, I cannot define its output size in the interface block.

To illustrate, this is a example code that doesn't work.

[plain]module solver_mod
 implicit none
 integer           :: nx,ny
 contains
  subroutine do_something(func)
    implicit none
    interface
      subroutine func(x,y)
        implicit none
        real,intent(in)               :: x(:)
        real,intent(out)              :: y(:)
      end subroutine func
    end interface          
    real,allocatable   :: x(:),y(:)
    integer            :: i
    allocate(x(nx),y(ny))
    forall (i = 1:nx) x(i) = 1.2*i
    call func(x,y)
    print *,' do_something: x = ',x
    print *,' do_something: y = ',y
  end subroutine do_something
end module solver_mod
!------------------------------
!   MAIN PROGRAM
!------------------------------
program test_func_passing
 use solver_mod
 implicit none
 real,allocatable :: x(:),y(:)
 integer          :: i
 nx = 3
 ny = 2
 allocate(x(nx),y(ny))
 forall (i = 1:nx) x(i) = 1.2*i
 call test_problem(x,y)
 print *,' x = ',x
 print *,' y = ',y
 call do_something(test_problem)
 contains
  subroutine test_problem(x,y)
    implicit none
    real,intent(in)              :: x(:)
    real,intent(out)             :: y(ny)
    integer                      :: i
    forall (i = 1:ny) y(i) = i*sum(x)
    print *,' test_problem: calculated y = ',y
  end subroutine test_problem
end program test_func_passing [/plain]


If I compile this with ifort, it compiles but I get segmentation fault during runtime.

I usually fix this by passing an additional argument to the function which will specify its output length, but this is normally unnecessary information on the side of the actual function.

So, this code works fine.

[plain]module solver_mod
 implicit none
 integer           :: nx,ny
 contains
  subroutine do_something(func)
    implicit none
    interface
      subroutine func(x,ny,y)
        implicit none
        real,intent(in)               :: x(:)
        integer,intent(in)            :: ny
        real,allocatable,intent(out)  :: y(:)
      end subroutine func
    end interface          
    real,allocatable   :: x(:),y(:)
    integer            :: i
    allocate(x(nx),y(ny))
    forall (i = 1:nx) x(i) = 1.2*i
    call func(x,ny,y)
    print *,' do_something: x = ',x
    print *,' do_something: y = ',y
  end subroutine do_something
end module solver_mod
!-----------------------------
!   MAIN PROGRAM
!-----------------------------
program test_func_passing
 use solver_mod
 implicit none
 real,allocatable :: x(:),y(:)
 integer          :: i
 nx = 3
 ny = 2
 allocate(x(nx),y(ny))
 forall (i = 1:nx) x(i) = 1.2*i
 call test_problem(x,ny,y)
 print *,' x = ',x
 print *,' y = ',y
 call do_something(test_problem)
 contains
  subroutine test_problem(x,ny,y)
    implicit none
    real,intent(in)              :: x(:)
    integer,intent(in)           :: ny
    real,allocatable,intent(out) :: y(:)
    integer                      :: i
    allocate(y(ny))
    forall (i = 1:ny) y(i) = i*sum(x)
    print *,' test_problem: calculated y = ',y
  end subroutine test_problem
end program test_func_passing [/plain]


Is there any way of doing this with without passing this additional argument?

Thanks a lot!
Grgur
0 Kudos
4 Replies
rreis
New Contributor I
523 Views
Quoting - gtokic

[plain]  subroutine test_problem(x,y)
implicit none
real,intent(in) :: x(:)
real,intent(out) :: y(ny)
integer :: i
forall (i = 1:ny) y(i) = i*sum(x)
print *,' test_problem: calculated y = ',y
end subroutine test_problem
end program test_func_passing [/plain]


in the first piece of code (above), you have

[plain]real,intent(out)             :: y(ny)[/plain]

instead of just "real,intent(out) :: y(:)"

and then you use "ny" again but I don't see how the subroutine knows about it. Am I overlooking something?
0 Kudos
gtokic
Beginner
523 Views
Quoting - rreis

in the first piece of code (above), you have

[plain]real,intent(out)             :: y(ny)[/plain]

instead of just "real,intent(out) :: y(:)"

and then you use "ny" again but I don't see how the subroutine knows about it. Am I overlooking something?

Hi Ricardo,

I'm not sure whether you're overlooking something or am I. The subroutine test_problem knows about ny since it's internal subroutine of the main program where ny is defined. Or at least that's my understanding. But since it doesn't work that way, I'm probably wrong. So any ideas would be really helpful.
0 Kudos
Ron_Green
Moderator
523 Views
Quoting - gtokic

Hi Ricardo,

I'm not sure whether you're overlooking something or am I. The subroutine test_problem knows about ny since it's internal subroutine of the main program where ny is defined. Or at least that's my understanding. But since it doesn't work that way, I'm probably wrong. So any ideas would be really helpful.

Yes, but think about when test_problem is COMPILED - what is the value of NY at compile-time? It's undefined.

I'm surprised the compiler didn't flag an error for this, as the value of NY must be defined at compile time (as in a PARAMETER statement) OR NY has to be passed as an parameter so the compiler knows to resolve the array at runtime.

And as Ricardo pointed out, the fix is to simply say

real, intent(out) :: y(:)

so the compiler knows that this array is resolved at runtime.

I'll get a bug report on this, as an error message from the compiler would have helped.

ron
0 Kudos
gtokic
Beginner
523 Views

Yes, but think about when test_problem is COMPILED - what is the value of NY at compile-time? It's undefined.

I'm surprised the compiler didn't flag an error for this, as the value of NY must be defined at compile time (as in a PARAMETER statement) OR NY has to be passed as an parameter so the compiler knows to resolve the array at runtime.

And as Ricardo pointed out, the fix is to simply say

real, intent(out) :: y(:)

so the compiler knows that this array is resolved at runtime.

I'll get a bug report on this, as an error message from the compiler would have helped.

ron

Thanks, I just realized what you're both saying. I thought I have to assign output size of the array, I didn't think it can take the size from the actual argument. Now that I run it with real,intent(out) :: y(:) it works.

Thanks a lot!
Grgur
0 Kudos
Reply