Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass allocatable arrays to subroutines in Fortran

Tags:

The following code is returning a Segmentation Fault because the allocatable array I am trying to pass is not being properly recognized (size returns 1, when it should be 3). In this page (http://www.eng-tips.com/viewthread.cfm?qid=170599) a similar example seems to indicate that it should work fine in F95; my code file has a .F90 extension, but I tried changing it to F95, and I am using gfortran to compile.

My guess is that the problem should be in the way I am passing the allocatable array to the subroutine; What am I doing wrong?

!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%!  PROGRAM test !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%!  IMPLICIT NONE  DOUBLE PRECISION,ALLOCATABLE :: Array(:,:)  INTEGER                      :: iii,jjj   ALLOCATE(Array(3,3))  DO iii=1,3  DO jjj=1,3     Array(iii,jjj)=iii+jjj     PRINT*,Array(iii,jjj)  ENDDO  ENDDO  CALL Subtest(Array)   END PROGRAM !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%!  SUBROUTINE Subtest(Array)  DOUBLE PRECISION,ALLOCATABLE,INTENT(IN) :: Array(:,:)  INTEGER                                 :: iii,jjj   PRINT*,SIZE(Array,1),SIZE(Array,2)  DO iii=1,SIZE(Array,1)  DO jjj=1,SIZE(Array,2)     PRINT*,Array(iii,jjj)  ENDDO  ENDDO   END SUBROUTINE !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%! 
like image 976
Nordico Avatar asked Oct 24 '12 22:10

Nordico


People also ask

How do I pass an array to a function in Fortran?

Most FORTRAN compilers pass arrays by passing the address of the array, in this case all subprograms that use the array will then work on the same (and only) copy. The FORTRAN standard allows array passing by another method called copying in/out or copy/restore.

How do I use Allocatable in Fortran?

Purpose. The ALLOCATABLE attribute allows you to declare an allocatable object. You can dynamically allocate the storage space of these objects by executing an ALLOCATE statement or by a derived-type assignment statement. If the object is an array, it is a deferred-shape array or an assumed-rank array.

How do I dynamically allocate an array in Fortran?

A dynamic array is an array, the size of which is not known at compile time, but will be known at execution time. Dynamic arrays are declared with the attribute allocatable. The rank of the array, i.e., the dimensions has to be mentioned however, to allocate memory to such an array, you use the allocate function.

What is deallocate in Fortran?

Purpose. The DEALLOCATE statement dynamically deallocates allocatable objects and pointer targets. A specified pointer becomes disassociated, while any other pointers associated with the target become undefined.


2 Answers

If a procedure has a dummy argument that is an allocatable, then an explicit interface is required in any calling scope.

(There are numerous things that require an explicit interface, an allocatable dummy is but one.)

You can provide that explicit interface yourself by putting an interface block for your subroutine inside the main program. An alternative and far, far, far better option is to put the subroutine inside a module and then USE that module in the main program - the explicit interface is then automatically created. There is an example of this on the eng-tips site that you provided a link to - see the post by xwb.

Note that it only makes sense for a dummy argument to have the allocatable attribute if you are going to do something related to its allocation status - query its status, reallocate it, deallocate it, etc.

like image 75
IanH Avatar answered Oct 25 '22 01:10

IanH


Please also note that your allocatable dummy argument array is declared with intent(in), which means its allocation status will be that of the associated actual argument (and it may not be changed during the procedure). The actual argument passed to your subroutine may be unallocated and therefore illegal to reference, even with an explicit interface. The compiler will not know this and the behaviour of inquiries like size is undefined in such cases.

Hence, you first have to check the allocation status of array with allocated(array) before referencing its contents. I would further suggest to implement loops over the full array with lbound and ubound, since in general you can't be sure about array's bounds:

subroutine subtest(array)   double precision, allocatable, intent(in) :: array(:,:)   integer                                   :: iii, jjj    if(allocated(array)) then     print*, size(array, 1), size(array, 2)     do iii = lbound(array, 1), ubound(array, 1)       do jjj = lbound(array, 2), ubound(array, 2)         print*, array(iii,jjj)       enddo     enddo   endif   end subroutine 
like image 34
sigma Avatar answered Oct 25 '22 01:10

sigma