Declare explicit shape arrays from assumed shape arrays size

Dear all,

I am trying to make my subroutine like this:

subroutine doubleSum(data,nan)
  real, optional       :: nan
  real, intent(in out) :: data(:,:)
  integer, parameter   :: nx= size(data,1), ny = size(data,2)
  double precision     :: dData(nx,ny)

  dData = dble(data)
  print *,sum(dData) / (nx*ny)
end subroutine doubleSum

When I compile this, I get the following message:

PGF90-S-0087-Non-constant expression where constant expression required (doubleSum.f90: 4)
PGF90-S-0087-Non-constant expression where constant expression required (doubleSum.f90: 4)
PGF90-W-0435-Array declared with zero size (doubleSum.f90: 5)
PGF90-W-0435-Array declared with zero size (doubleSum.f90: 5)
0 inform, 2 warnings, 2 severes, 0 fatal for doublesum

It compiles and works fine in gfortran. Does anybody have any idea how to make this work in PGI fortran as well? The same code should work in both compilers.

It just puzzles me…

Thanks for your suggestions,
Vandome

Hi vandome,

What version of gfortran are you using? Most compilers including newer gfortran (4.3.2) will give a syntax error since the size of data isn’t known until runtime. To fix the code, allocate dData at runtime:

% cat test.f90
module foo
contains
subroutine doubleSum(data)
  real, intent(in out) :: data(:,:)
  integer   :: nx,ny
  double precision,allocatable,dimension(:,:)     :: dData
  nx= size(data,1)
  ny= size(data,2)
  allocate(dData(nx,ny))
  dData = dble(data)
  print *,sum(dData) / (nx*ny), nx, ny
  deallocate(dData)
end subroutine doubleSum

end module foo

program test
  use foo
  real, dimension(64,64) :: data
  data=1.1
  call doubleSum(data)
end program test
% pgf90 test.f90 ; a.out
    1.100000023841858                64           64
  • Mat

Hello Mat, thank you for your quick answer. I am running gfortran 4.1.2 on CentOS 5.4. So that explains why it worked until now. A pity it is not possible anymore since I really wanted to avoid using allocatables.

The reason is that I usually encounter the “cannot allocate an already allocated array” error, even though I deallocated the array.

Your subroutine works perfectly, however, when I want to pass an array using a function, the only solution I found is using pointers resulting in serious headaches:

module foo 
contains 
function doubleSum(data) result(dData_)
  real, intent(in) :: data(:,:)
  integer :: nx,ny
  double precision,dimension(:,:),pointer :: dData_
  double precision, dimension(:,:), allocatable, target :: dData
  save dData

  nx= size(data,1)
  ny= size(data,2)

  allocate(dData(nx,ny))
  dData = dble(data)
  dData = dData + 0.01

  dData_ => dData

  print *,'in function', dData(1,5)
end function doubleSum
end module foo


program test 
  use foo 
  real, dimension(64,64) :: data
  double precision, pointer, dimension(:,:) :: data_
  data = 1.1

  data_ => doubleSum(data)

  print *,'in main program', data_(1,5)

  deallocate(data_)
  nullify(data_)
end program test

This is so inconvenient because the user of the function needs to deallocate the pointer him/herself.

And although this works fine in gfortran, pgi fortran tends to create memory leaks with this solution.
(See allocatable function result)

Is there any way to make this easier?

Hi Vandome,

You can use F2003 allocatable semantics to simplify this code. Note that by default use use F95 semantics since F2003 semantics can have a detrimental performance impact.

Example:

% cat test6.f90 
module foo
contains
function doubleSum(data) result(dData)
  real, intent(in) :: data(:,:)
  integer :: nx,ny
  double precision, dimension(:,:), allocatable :: dData

  nx= size(data,1)
  ny= size(data,2)

  dData = dble(data)
  dData = dData + 0.01
  print *,'in function', dData(1,5)
end function doubleSum
end module foo


program test
  use foo
  real, dimension(64,64) :: data
  data = 1.1

  data=doubleSum(data)

  print *,'in main program', data(1,5)

end program test 

% pgf90 test6.f90 -Mallocatable=03 -fast -V11.4
% valgrind a.out
==19564== Memcheck, a memory error detector.
==19564== Copyright (C) 2002-2006, and GNU GPL'd, by Julian Seward et al.
==19564== Using LibVEX rev 1658, a library for dynamic binary translation.
==19564== Copyright (C) 2004-2006, and GNU GPL'd, by OpenWorks LLP.
==19564== Using valgrind-3.2.1, a dynamic binary instrumentation framework.
==19564== Copyright (C) 2000-2006, and GNU GPL'd, by Julian Seward et al.
==19564== For more details, rerun with: -v
==19564== 
--19564-- DWARF2 CFI reader: unhandled CFI instruction 0:7
--19564-- DWARF2 CFI reader: unhandled CFI instruction 0:7
 in function    1.110000023618340     
 in main program    1.110000    
==19564== 
==19564== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 5 from 1)
==19564== malloc/free: in use at exit: 1,105,216 bytes in 4 blocks.
==19564== malloc/free: 6 allocs, 2 frees, 1,106,176 bytes allocated.
==19564== For counts of detected errors, rerun with: -v
==19564== searching for pointers to 4 not-freed blocks.
==19564== checked 1,570,888 bytes.
==19564== 
==19564== LEAK SUMMARY:
==19564==    definitely lost: 0 bytes in 0 blocks.
==19564==      possibly lost: 0 bytes in 0 blocks.
==19564==    still reachable: 1,105,216 bytes in 4 blocks.
==19564==         suppressed: 0 bytes in 0 blocks.
==19564== Reachable blocks (those to which a pointer was found) are not shown.
==19564== To see them, rerun with: --show-reachable=yes

Hope this helps,
Mat

Hello again Mat,

Thank you very much for your clear answer. This is definitely useful! I will study these F2003 semantics a bit more. They seem to have potential…
I wonder if the detrimental performance impact you are talking about is significant when using smp or mpi.