The argument of my fortran 95 subroutine is an assumed shape array with intent inout:
the_subroutine(my_argument)
real, dimension(:,:), intent(inout) :: my_argument
(...)
In the main program, I have an allocatable array. I allocate it and also rename indexes. Then I call the subroutine and pass that (correctly allocated) array to the subroutine:
allocate(the_array( 5:1005 , 5:1005 ))
call the_subroutine(my_argument=the_array)
The subroutine does certain calculations and fills the array with values. In the very last line before the end of the subroutine, I check a random value:
(...)
print*, my_argument(213,126) ! I get 2.873...
end subroutine the_subroutine
Then, in the very first line after the subroutine call, I check if the value has been correctly communicated by the subroutine to the outer world, but that is not the case:
call the_subroutine(my_argument=the_array)
print*, the_array(213,126) ! I get 3.798... A completely different value.
The problem arises from having re-indexed the array in the main program as:
allocate(the_array( 5:1005 , 5:1005 ))
where max_index - min_index = 1000-1, but the subroutine "sees" the array internally as if I had declared the normal way, i.e.:
allocate(the_array( 1:1000, 1:1000))
Or simply, allocate(the_array( 1000, 1000 ))
Therefore, the element (213,126) in the internal array is in another location as in the main program array. Is there any easy way out of this?
The default lower bound for an assumed shape array is one.
If you want a different lower bound, then you need to declare the array dummy argument appropriately.
subroutine the_subroutine(my_argument)
real, dimension(5:,5:), intent(inout) :: my_argument
! ^ ^
(The rules for the bounds of the dummy argument are different for deferred shape arrays - array dummy arguments which also have the POINTER or ALLOCATABLE attributes.)
use lbound
to pass the bounds to the subroutine:
implicit none
real,allocatable:: x(:,:)
allocate(x(5:10,5:10))
call sub(x,lbound(x))
write(*,*)'o',x(5,5)
contains
subroutine sub(x,lb)
implicit none
integer lb(2)
real, dimension(lb(1):,lb(2):)::x
x(5,5)=42.
end subroutine
end
o 42.0000
Finally, I found the solution.
First, if working in Fortran 2003 (or Fortran 95 with non-standard extensions), you may simply declare the assumed shape argument in the subroutine as ALLOCATABLE:
subroutine the_subroutine(my_argument)
real, dimension(:,:), allocatable, intent(inout) :: my_argument
Then the subroutine "sees" the renamed index correctly. However this is not allowed in the Fortran 95 standard.
In Fortran 95, the most elegant way I found for this is by making use of a pointer:
program example
implicit none
real, dimension(:,:), allocatable, target :: the_array
real, dimension(:,:), pointer :: the_pointer
[...]
allocate(the_array(5:1005,5:1005))
the_pointer => the_array
call the_subroutine(my_argument=the_pointer)
And in the subroutine:
subroutine the_subroutine(my_argument)
real, dimension(:,:), pointer :: my_argument
Then it works perfectly. Inside the subroutine, MY_ARGUMENT is treated exactly as if it was an assumed shape array.
another approach to the problem: make the array a derived type and the subroutine a method of the type:
module example
implicit none
type a
real, allocatable::y(:,:)
end type a
contains
subroutine sub(this)
type(a)::this
write(*,*)lbound(this%y)
end subroutine
end module
program p
use example
implicit none
type (a) my_array
allocate(my_array%y(5:6,7:8))
call sub(my_array)
deallocate(my_array%y)
allocate(my_array%y(2:3,1:2))
call sub(my_array)
end
5 7
2 1
as you see now the subroutine automatically knows the correct dimensions. Obviously now the subroutine can only work with the derived type array.