Repeatedly used 2D array in a Fortran 90 subroutine - fortran

I have a Fortran 90 program that is of the structure shown below. The step compute the 2D array myMatrix(1:N,1:N) in the subroutinne A is expensive. It depends only on the global variable N and it needs to be computed only once; the "other steps" in the subroutine will not change the value of myMatrix. Currently, myMatrix will be calculated whenever the subroutine is called.
Is there a way to write the program in a way that the 2D array myMatrix is calculated only once?
module constants
integer :: N
end module constans
module A_module
use constants
contains
subroutine A
! compute the 2D real array myMatrix(1:N,1:N)
! other steps that use myMatrix
end subroutine A
end module A_module
program main
use constants
use A_module
integer :: k
do k = 1,10000
call A
end do
end program main

Sure. Definite an init_a_matrix subroutine that initializes the matrix outside of the do loop.
subroutine init_a_matrix
! Do initialization here
end subroutine init_a_matrix
Then you have
call init_a_matrix
do k = 1,10000
call A
end do
If you want to eliminate the redundant initialization of myMatrix in the subroutine A (since it only needs to be calculated once, upon the initial call of the subroutine), you can use the SAVE attribute and a LOGICAL flag. In subroutine A you do,
logical :: init_flag = .false.
real, save :: matrix_a(n,n)
if (init_flag .eqv. .false.) then
! Initialize matrix_a on the first call to the subroutine and reset init_flag.
init_flag = .true.
end if

If myMatrix is an unsaved, local variable of the subroutine A, then it will be necessary to recalculate its values on each entry of the subroutine: unsaved local variables become undefined when the subroutine completes execution.
However, there are a number of approaches to reuse the variable:
make it a saved local variable: saved local variables retain their definition
have it as a dummy argument, not a local variable (argument association): its definition comes from the caller
have it as some other form of non-local variable (other forms of association): its definition comes from another place
If it's a saved variable, compute it on the first entry to the subroutine and retains its definition on subsequent calls:
subroutine A
<declaration>, save :: mymatrix
logical, save :: first_entry = .TRUE.
if (first_entry) then
! set up mymatrix
first_entry = .FALSE.
end if
! ...
end subroutine A
You can do much the same with mymatrix a module/host variable. You can either use the first_entry saved indicator or rely on the user (as in evets's answer) having an extra setup step:
module A_module
use constants
<declaration> myMatrix ! Example with host association, automatically saved
contains
subroutine A
! myMatrix is reused, either set up by a distinct call or on first entry
! other steps that use myMatrix
end subroutine A
end module A_module
Or you can have the variable as a dummy argument:
mymatrix_actual = ...
do k = 1,10000
call A(mymatrix_actual) ! A now has the dummy variable
end do

Related

Why an allocated array gets unallocated when it is passed to a subroutine?

Passing an allocatable array via actual argument to a subroutine whose corresponding dummy argument is defined as an allocatable array:
module m
real, allocatable :: a(:,:)
end module m
module m2
contains
subroutine p(c)
implicit none
real, allocatable, intent(out):: c(:,:)
write(*,*) 'allocated?=', allocated(c)
end subroutine p
end module m2
program main
use m, only : a
use m2, only: p
implicit none
allocate(a(3,3))
write(*,*) 'allocated?=', allocated(a)
call p(a)
end program main
The output:
allocated?= T
allocated?= F
The first is as expected, but why the allocated status becomes false, as is indicated by the second output?
Allocatable dummy arguments that have intent(out) are automatically deallocated when the procedure is entered according to thevstandard. The intent also affects the allocation status, not just the values inside.
It actually makes a very good sense. If it is intent(out), any previous allocation status should not matter.

Initialization of 2d arrays within subroutines [duplicate]

I have a Fortran 90 program that is of the structure shown below. The step compute the 2D array myMatrix(1:N,1:N) in the subroutinne A is expensive. It depends only on the global variable N and it needs to be computed only once; the "other steps" in the subroutine will not change the value of myMatrix. Currently, myMatrix will be calculated whenever the subroutine is called.
Is there a way to write the program in a way that the 2D array myMatrix is calculated only once?
module constants
integer :: N
end module constans
module A_module
use constants
contains
subroutine A
! compute the 2D real array myMatrix(1:N,1:N)
! other steps that use myMatrix
end subroutine A
end module A_module
program main
use constants
use A_module
integer :: k
do k = 1,10000
call A
end do
end program main
Sure. Definite an init_a_matrix subroutine that initializes the matrix outside of the do loop.
subroutine init_a_matrix
! Do initialization here
end subroutine init_a_matrix
Then you have
call init_a_matrix
do k = 1,10000
call A
end do
If you want to eliminate the redundant initialization of myMatrix in the subroutine A (since it only needs to be calculated once, upon the initial call of the subroutine), you can use the SAVE attribute and a LOGICAL flag. In subroutine A you do,
logical :: init_flag = .false.
real, save :: matrix_a(n,n)
if (init_flag .eqv. .false.) then
! Initialize matrix_a on the first call to the subroutine and reset init_flag.
init_flag = .true.
end if
If myMatrix is an unsaved, local variable of the subroutine A, then it will be necessary to recalculate its values on each entry of the subroutine: unsaved local variables become undefined when the subroutine completes execution.
However, there are a number of approaches to reuse the variable:
make it a saved local variable: saved local variables retain their definition
have it as a dummy argument, not a local variable (argument association): its definition comes from the caller
have it as some other form of non-local variable (other forms of association): its definition comes from another place
If it's a saved variable, compute it on the first entry to the subroutine and retains its definition on subsequent calls:
subroutine A
<declaration>, save :: mymatrix
logical, save :: first_entry = .TRUE.
if (first_entry) then
! set up mymatrix
first_entry = .FALSE.
end if
! ...
end subroutine A
You can do much the same with mymatrix a module/host variable. You can either use the first_entry saved indicator or rely on the user (as in evets's answer) having an extra setup step:
module A_module
use constants
<declaration> myMatrix ! Example with host association, automatically saved
contains
subroutine A
! myMatrix is reused, either set up by a distinct call or on first entry
! other steps that use myMatrix
end subroutine A
end module A_module
Or you can have the variable as a dummy argument:
mymatrix_actual = ...
do k = 1,10000
call A(mymatrix_actual) ! A now has the dummy variable
end do

How to pass a function with multiple arguments to a subroutine that expects a function with only one argument?

I have a subroutine (minimal example)
subroutine treatfunction(f,input,output)
external, real::f
real, intent(in):: input
real, intent(out):: output
output = f(input) + f(1.0) ! i.e. f has only one argument
end subroutine
and a function with two arguments
real function fun(x,a)
real,intent(in)::x,a
Now for a given a fixed at runtime, I want to pass fun to treatfunction. So ideally, I would want to call something like
call treatfunction(fun(:,a=a0), input=myinput, output=myoutput)
What is the most elegant way of doing this with the Fortran2003 features gfortran-5 supports?
Of course, I could insert an optional dummy argument a in treatfunction and call f either with f(x) or f(x,a) depending on present(a) in the subroutine's body. But changing the subroutine is not elegant.
In Fortran 2008 you can pass internal functions as arguments and gfortran supports it.
subroutine calling()
a0 = ...
call treatfunction(wrapper, input=myinput, output=myoutput)
contains
real function wrapper(x)
real, intent(in) :: x
wrapper = fun(x,a0)
end function
end subroutine
BTW, I would stay away from external it is evil, use interface blocks.

Memory trouble when deallocating Fortran linked list,

I have implemented a generic linked list (genII.f90) written in Fortran found in
http://fortranwiki.org/fortran/show/Linked+list .
I test it and everything is ok except the fact that the LI_Remove_Head function seems not to free the memory.
I add to the original module the function LI_Destruct (see below) and same result it does not free the memory.
SUBROUTINE LI_Destruct(List)
implicit none
TYPE(List_Type),INTENT(INOUT),TARGET :: List
TYPE(Link_Ptr_Type) :: Link_current, Link_next
Link_next%P =>List%Head%next
do while (associated(Link_next%P))
Link_current%P => Link_next%P
Link_next%P => Link_next%P%next
deallocate(Link_current%P)
end do
end subroutine LI_destruct
I certainly miss something so my questions are two:
1- Is there an error in the code? For what reason the memory is not emptied by the "deallocate"?
2- Does it exist better and almost standard generic linked list for fortran?
I add the simple code below used to do the test:
PROGRAM test_list
! Defines data and other list(s) and arrays for particles.
USE Generic_List, ONLY : Link_Ptr_Type,Link_Type,List_Type
USE Generic_List, ONLY : LI_Init_List,LI_Add_To_Head,LI_Add_To_Tail,LI_Get_Head,&
LI_Remove_Head,LI_Get_Next,LI_Associated,LI_Get_Len, LI_destruct
IMPLICIT NONE
TYPE:: Particle_data
REAL, dimension(2) :: pos !! Coordinate dimensionali
END TYPE Particle_data
! Definition of the types necessary for the list
TYPE Particle_Node
TYPE(Link_Type) :: Link
TYPE(Particle_data), pointer :: Data
END TYPE Particle_Node
TYPE Particle_Node_ptr
TYPE(Particle_Node), pointer :: P
END TYPE Particle_Node_ptr
! Create array of lists in order to allow classify the particles
TYPE(List_Type), allocatable :: ao_Particle_List(:)
TYPE(Link_Ptr_Type) :: Link
TYPE(Particle_Node_ptr) :: Particle_elem
!-------------------------------------------------------------!
!-------------------------------------------------------------!
INTEGER, parameter :: Npart_test = 1000000 ! , nPart
INTEGER :: i,iter,j,item,nBuffer
REAL :: pos(2)
nBuffer = 5
IF (ALLOCATED(ao_Particle_List)) DEALLOCATE(ao_Particle_List)
ALLOCATE(ao_Particle_List(0:nBuffer))
! Init list used for temporary construction
DO iter=0,nBuffer
CALL LI_Init_List(ao_Particle_List(iter))
ENDDO
DO j=1,NBuffer
DO i=1,Npart_test
pos(1)=i*1.0; pos(2)=j*i
ALLOCATE(Particle_elem%P); ALLOCATE(Particle_elem%P%Data) ! Allocate data before store
Particle_elem%P%Data%pos = pos
! Elem is treated and should be put at head of the list ao_Particle_List(item)
item=j
Link = TRANSFER(Particle_elem,Link); CALL LI_Add_To_Head(Link,ao_Particle_List(item)) ! STORAGE
END DO
END DO
WRITE(*,*) "List is full, see RAM"; READ(*,*)
! Write(*,*) "Destruct list"
DO iter=0,nBuffer
CALL LI_Destruct(ao_Particle_List(iter))
ENDDO
IF (ALLOCATED(ao_Particle_List)) DEALLOCATE(ao_Particle_List)
WRITE(*,*) "List is empty, see RAM"; READ(*,*)
END PROGRAM
Thanks to all,
John
OK the problem is solved. As there is a transfer operation it seems that the data cannot be reached in the function LI_DESTRUCT done.
The correct way to deallocate the linked list is (slightly different as the example in fortran wiki) is:
DO
Link = LI_Remove_Head(ao_Particle_List)
IF(.NOT.LI_Associated(Link))EXIT
User = TRANSFER(Link,User)
!~ WRITE(6,*)User%P%Data%Index,User%P%Data%User_Stuff
DEALLOCATE(User%P%Data)
DEALLOCATE(User%P)
ENDDO

changing array dimensions in fortran

There are basically two ways to pass arrays to a subroutine in Fortran 90/95:
PROGRAM ARRAY
INTEGER, ALLOCATABLE :: A(:,:)
INTEGER :: N
ALLOCATE(A(N,N))
CALL ARRAY_EXPLICIT(A,N)
! or
CALL ARRAY_ASSUMED(A)
END PROGRAM ARRAY
SUBROUTINE ARRAY_EXPLICIT(A,N)
INTEGER :: N
INTEGER :: A(N,N)
! bla bla
END SUBROUTINE ARRAY_EXPLICIT
SUBROUTINE ARRAY_ASSUMED(A)
INTEGER, ALLOCATABLE :: A(:,:)
N=SIZE(A,1)
! bla bla
END SUBROUTINE ARRAY_ASSUMED
where you need an explicit interface for the second, usually through the use of a module.
From FORTRAN77, I'm used to the first alternative, and I read this is also the most efficient if you pass the whole array.
The nice thing with the explicit shape is that I can also call a subroutine and treat the array as a vector instead of a matrix:
SUBROUTINE ARRAY_EXPLICIT(A,N)
INTEGER :: N
INTEGER :: A(N**2)
! bla bla
END SUBROUTINE ARRAY_EXPLICIT
I wondered if there is a nice way to do that kind of thing using the second, assumed shape interface, without copying it.
See the RESHAPE intrinsic, e.g.
http://gcc.gnu.org/onlinedocs/gfortran/RESHAPE.html
Alternatively, if you want to avoid the copy (in some cases an optimizing compiler might be able to do a reshape without copying, e.g. if the RHS array is not used afterwards, but I wouldn't count on it), as of Fortran 2003 you can assign pointers to targets of different rank, using bounds remapping. E.g. something like
program ptrtest
real, pointer :: a(:)
real, pointer :: b(:,:)
integer :: n = 10
allocate(a(n**2))
a = 42
b (1:n, 1:n) => a
end program ptrtest
I was looking to do the same thing and came across this discussion. None of the solutions suited my purposes, but I found that there is a way to reshape an array without copying the data using iso_c_binding if you are using the fortran 2003 standard which current fortran 90/95 compilers tend to support. I know the discussion is old, but I figured I would add what I came up with for the benefit of others with this question.
The key is to use the function C_LOC to convert an array to an array pointer, and then use C_F_POINTER to convert this back into a fortran array pointer with the desired shape. One challenge with using C_LOC is that C_LOC only works for array that have a directly specified shape. This is because arrays in fortran with an incomplete size specification (i.e., that use a : for some dimension) include an array descriptor along with the array data. C_LOC does not give you the memory location of the array data, but the location of the descriptor. So an allocatable array or a pointer array don't work with C_LOC (unless you want the location of the compiler specific array descriptor data structure). The solution is to create a subroutine or function that receives the array as an array of fixed size (the size really doesn't matter). This causes the array variable in the function (or subroutine) to point to the location of the array data rather than the location of the array descriptor. You then use C_LOC to get a pointer to the array data location and C_F_POINTER to convert this pointer back into an array with the desired shape. The desired shape must be passed into this function to be used with C_F_POINTER. Below is an example:
program arrayresize
implicit none
integer, allocatable :: array1(:)
integer, pointer :: array2(:,:)
! allocate and initialize array1
allocate(array1(6))
array1 = (/1,2,3,4,5,6/)
! This starts out initialized to 2
print *, 'array1(2) = ', array1(2)
! Point array2 to same data as array1. The shape of array2
! is passed in as an array of intergers because C_F_POINTER
! uses and array of intergers as a SIZE parameter.
array2 => getArray(array1, (/2,3/))
! Change the value at array2(2,1) (same as array1(2))
array2(2,1) = 5
! Show that data in array1(2) was modified by changing
! array2(2,1)
print *, 'array(2,1) = array1(2) = ', array1(2)
contains
function getArray(array, shape_) result(aptr)
use iso_c_binding, only: C_LOC, C_F_POINTER
! Pass in the array as an array of fixed size so that there
! is no array descriptor associated with it. This means we
! can get a pointer to the location of the data using C_LOC
integer, target :: array(1)
integer :: shape_(:)
integer, pointer :: aptr(:,:)
! Use C_LOC to get the start location of the array data, and
! use C_F_POINTER to turn this into a fortran pointer (aptr).
! Note that we need to specify the shape of the pointer using an
! integer array.
call C_F_POINTER(C_LOC(array), aptr, shape_)
end function
end program
#janneb has already answered re RESHAPE. RESHAPE is a function -- usually used in an assignment statement so there will be a copy operation. Perhaps it can be done without copying using pointers. Unless the array is huge, it is probably better to use RESHAPE.
I'm skeptical that the explicit shape array is more efficient than the assumed shape, in terms of runtime. My inclination is to use the features of the Fortran >=90 language and use assumed shape declarations ... that way you don't have to bother passing the dimensions.
EDIT:
I tested the sample program of #janneb with ifort 11, gfortran 4.5 and gfortran 4.6. Of these three, it only works in gfortran 4.6. Interestingly, to go the other direction and connect a 1-D array to an existing 2-D array requires another new feature of Fortran 2008, the "contiguous" attribute -- at least according to gfortran 4.6.0 20110318. Without this attribute in the declaration, there is a compile time error.
program test_ptrs
implicit none
integer :: i, j
real, dimension (:,:), pointer, contiguous :: array_twod
real, dimension (:), pointer :: array_oned
allocate ( array_twod (2,2) )
do i=1,2
do j=1,2
array_twod (i,j) = i*j
end do
end do
array_oned (1:4) => array_twod
write (*, *) array_oned
stop
end program test_ptrs
You can use assumed-size arrays, but it can mean multiple layers of wrapper
routines:
program test
implicit none
integer :: test_array(10,2)
test_array(:,1) = (/1, 2, 3, 4, 5, 6, 7, 8, 9, 10/)
test_array(:,2) = (/11, 12, 13, 14, 15, 16, 17, 18, 19, 20/)
write(*,*) "Original array:"
call print_a(test_array)
write(*,*) "Reshaped array:"
call print_reshaped(test_array, size(test_array))
contains
subroutine print_reshaped(a, n)
integer, intent(in) :: a(*)
integer, intent(in) :: n
call print_two_dim(a, 2, n/2)
end subroutine
subroutine print_two_dim(a, n1, n2)
integer, intent(in) :: a(1:n1,1:*)
integer, intent(in) :: n1, n2
call print_a(a(1:n1,1:n2))
end subroutine
subroutine print_a(a)
integer, intent(in) :: a(:,:)
integer :: i
write(*,*) "shape:", shape(a)
do i = 1, size(a(1,:))
write(*,*) a(:,i)
end do
end subroutine
end program test
I am using ifort 14.0.3 and 2D to 1D conversion, I could use an allocatable array for 2D array and a pointer array for 1D:
integer,allocatable,target :: A(:,:)
integer,pointer :: AP(:)
allocate(A(3,N))
AP(1:3*N) => A
As #M.S.B mentioned, in case both A and AP have the pointer attribute, I had to use contiguous attribute for A to guarantee the consistency of the conversion.
Gfortran is a bit paranoid with interfaces. It not only wants to know the type, kind, rank and number of arguments, but also the shape, the target attribute and the intent (although I agree with the intent part). I encountered a similar problem.
With gfortran, there are three different dimension definition:
1. Fixed
2. Variable
3. Assumed-size
With ifort, categories 1 and 2 are considered the same, so you can do just define any dimension size as 0 in the interface and it works.
program test
implicit none
integer, dimension(:), allocatable :: ownlist
interface
subroutine blueprint(sz,arr)
integer, intent(in) :: sz
integer, dimension(0), intent(in) :: arr
! This zero means that the size does not matter,
! as long as it is a one-dimensional integer array.
end subroutine blueprint
end interface
procedure(blueprint), pointer :: ptr
allocate(ownlist(3))
ownlist = (/3,4,5/)
ptr => rout1
call ptr(3,ownlist)
deallocate(ownlist)
allocate(ownlist(0:10))
ownlist = (/3,4,5,6,7,8,9,0,1,2,3/)
ptr => rout2
call ptr(3,ownlist)
deallocate(ownlist)
contains
! This one has a dimension size as input.
subroutine rout1(sz,arr)
implicit none
integer, intent(in) :: sz
integer, dimension(sz), intent(in) :: arr
write(*,*) arr
write(*,*) arr(1)
end subroutine rout1
! This one has a fixed dimension size.
subroutine rout2(sz,arr)
implicit none
integer, intent(in) :: sz
integer, dimension(0:10), intent(in) :: arr
write(*,*) "Ignored integer: ",sz
write(*,*) arr
write(*,*) arr(1)
end subroutine rout2
end program test
Gfortran complains about the interface. Changing the 0 into 'sz' solves the problem four 'rout1', but not for 'rout2'.
However, you can fool gfortran around and say dimension(0:10+0*sz) instead of dimension(0:10) and gfortran compiles and gives the same
result as ifort.
This is a stupid trick and it relies on the existence of the integer 'sz' that may not be there. Another program:
program difficult_test
implicit none
integer, dimension(:), allocatable :: ownlist
interface
subroutine blueprint(arr)
integer, dimension(0), intent(in) :: arr
end subroutine blueprint
end interface
procedure(blueprint), pointer :: ptr
allocate(ownlist(3))
ownlist = (/3,4,5/)
ptr => rout1
call ptr(ownlist)
deallocate(ownlist)
allocate(ownlist(0:10))
ownlist = (/3,4,5,6,7,8,9,0,1,2,3/)
ptr => rout2
call ptr(ownlist)
deallocate(ownlist)
contains
subroutine rout1(arr)
implicit none
integer, dimension(3), intent(in) :: arr
write(*,*) arr
write(*,*) arr(1)
end subroutine rout1
subroutine rout2(arr)
implicit none
integer, dimension(0:10), intent(in) :: arr
write(*,*) arr
write(*,*) arr(1)
end subroutine rout2
end program difficult_test
This works under ifort for the same reasons as the previous example, but gfortran complains about the interface. I do not know how I can fix it.
The only thing I want to tell gfortran is 'I do not know the dimension size yet, but we will fix it.'. But this needs a spare integer arguemnt (or something else that we can turn into an integer) to fool gfortran around.