The routine does not return the correct numeric values ​​in the intended array of the form due to the renaming of the index in the main program

The argument to my fortran 95 routine is the intended array of the form with the intent inout:

the_subroutine(my_argument) real, dimension(:,:), intent(inout) :: my_argument (...) 

In the main program, I have a allocated array. I highlight it and also rename indexes . Then I call the subroutine and pass this (correctly allocated) array to the subroutine:

 allocate(the_array( 5:1005 , 5:1005 )) call the_subroutine(my_argument=the_array) 

The routine performs certain calculations and populates the array with values. In the very last line, until 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 calling the subroutine , I will check whether this value is correctly transferred by the subroutine to the outside world, but this is not so:

 call the_subroutine(my_argument=the_array) print*, the_array(213,126) ! I get 3.798... A completely different value. 

The problem arises due to reindexing the array in the main program as follows:

 allocate(the_array( 5:1005 , 5:1005 )) 

where max_index is min_index = 1000-1, but the routine "sees" the array internally, as if I had declared a normal path, that is:

 allocate(the_array( 1:1000, 1:1000)) 

Or just select (the_array (1000, 1000))

Therefore, the element (213,126) in the internal array is in a different place, as in the main program array. Is there a simple way out of this?

+1
source share
4 answers

Finally, I found a solution.

First, if you are working in Fortran 2003 (or Fortran 95 with non-standard extensions), you can simply declare the alleged form argument in the routine as ALLOCATABLE:

 subroutine the_subroutine(my_argument) real, dimension(:,:), allocatable, intent(inout) :: my_argument 

Then the routine β€œsees” the renamed index correctly. However, this is not allowed in the Fortran 95 standard.

In Fortran 95, the most elegant way I've found to do this is to use 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 fine. Inside the subroutine, MY_ARGUMENT is processed exactly as if it were the intended array of the form.

0
source

The default lower bound for the proposed form array is one.

If you need another lower bound, you need to declare the argument of the array argument accordingly.

 subroutine the_subroutine(my_argument) real, dimension(5:,5:), intent(inout) :: my_argument ! ^ ^ 

(The rules for the boundaries of a dummy argument are different for deferred form arrays β€” array arguments that also have POINTER or ALLOCATABLE attributes.)

+2
source

use lbound to pass evaluations to the routine:

  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

+1
source

another approach to the problem: make the array a derived type and a subroutine a method of 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 now see, the subroutine automatically knows the correct sizes. Obviously, now a routine can only work with an array of a derived type.

0
source

Source: https://habr.com/ru/post/1013019/


All Articles