passing pointer arguments in fortran - pointers

I am wondering what is the proper way to write the following code?
PROGRAM foo
INTEGER :: x
REAL(KIND=8), TARGET, DIMENSION(0: 10) :: array
REAL(KIND=8), POINTER, DIMENSION(:) :: ptr
ptr => array
CALL bar(ptr)
END PROGRAM foo
SUBROUTINE bar (ptr)
REAL(KIND=8), POINTER, DIMENSION(:) :: ptr
INTEGER x
DO x =0, 10
ptr(x) = 2 // seg faults
ENDDO
END SUBROUTINE bar
It works if I declare ptr in bar as REAL(KIND=8), DIMENSION(0:10). But in general I might not know the size of the passed-in array, so is there a way to declare ptr to be a pointer to some array? I am compiling this with gfortran

If a procedure has a dummy argument that is a pointer, then an explicit interface is required in any calling scope.
(There are numerous things that require an explicit interface, a pointer 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. A third alternative is to make the subroutine an internal procedure of the calling scope.
As of Fortran 2003, you should only use pointers if you intend to point the pointer at different things. If you are just using the pointer for something that really just behaves like a value, then you should use allocatables instead.

It depends what you mean with "proper" way. As IanH already pointed out, you need an explicit interface (best done via packing things in a module) and using allocatables instead of pointers, if possible.
I'd further add, that if you do not want to change the allocation status of your array within your subroutine, but only want to manipulate its elements, then use a simple assumed shape array within your subroutine. Below you find a working example for it. A few more things to note:
Do not use real(kind=8) as not all compilers use the number of bytes as kind for the real numbers. If you want double precision accuracy, ask for it explicitely as below.
If you just want to fill up an array with a constant value, do it the simple way: array(:) = 2.0_dp
And here the example:
module accuracy
implicit none
integer, parameter :: dp = kind(1.0d0)
end module accuracy
module barmodule
use accuracy
implicit none
contains
subroutine bar(array)
real(dp), intent(inout) :: array(:)
integer :: ii
do ii = 1, size(array)
array(ii) = ii
end do
end subroutine bar
end module barmodule
program foo
use accuracy
use barmodule
implicit none
real(dp), dimension(0:10) :: array
call bar(array)
end program foo

Related

Passing Fortran POINTER to SUBROUTINES as MODULE PROCEDURE

My first question is, "Can POINTER be passed to subroutines next to INTENT?"
Although passing Fortran POINTER with INTENT(IN) or INTENT(INOUT) seems to be a common practice, the documentation of Intel for Fortran POINTER says(https://software.intel.com/content/www/us/en/develop/documentation/fortran-compiler-developer-guide-and-reference/top/language-reference/a-to-z-reference/o-to-p/pointer-fortran.html)
The pointer cannot be declared with the INTENT or PARAMETER attributes
which confuses me a lot.
My second question is related to following code.
I tried overloading write_matrix with write_matrix_2d - which is for 2d arrays - and write_matrix_2d_ptr - which is for 2d Fortran POINTERs.
It turned out the code fails to compile with
Ambiguous generic interface WRITE_MATRIX: previously declared specific procedure WRITE_MATRIX_2D is not distinguishable from this declaration. [WRITE_MATRIX_2D_PTR]
If I comment (1) then it complies, and runs fine ( but I suppose this is bad practice since POINTER arguments going into subroutien write_matrix_2d which expects array input.)
Is there any way to overload Fortran subroutines just by their arguments' datatype just like C/C++?
module mod_write
implicit none
interface write_matrix
module procedure write_matrix_2d
(1) !module procedure write_matrix_2d_ptr
end interface
contains
subroutine write_matrix_2d(a)
implicit none
real, intent(in) :: a(:,:)
! local variables
integer :: i, j
print *, "in ARRAY printing subroutine"
do i = lbound(a,1), ubound(a,1)
write(*,*) ( a(i,j), j = lbound(a,2), ubound(a,2) )
enddo
end subroutine
subroutine write_matrix_2d_ptr(a)
implicit none
real, pointer, intent(in) :: a(:,:)
! local variables
integer :: i, j
print *, "in POINTER printing subroutine"
do i = lbound(a,1), ubound(a,1)
write(*,*) ( a(i,j), j = lbound(a,2), ubound(a,2) )
enddo
end subroutine
end module
program test
use mod_write
implicit none
real, dimension(9) :: b = (/21, 22, 23, 24, 25, 26, 27, 28, 29/)
real, dimension(3,3) :: c
real, dimension(3,3), target :: ct(3,3)
real, dimension(:,:), pointer :: cptr(:,:)
c = reshape( b, (/3, 3/) )
write(*,*)
write(*,*) 'c'
call write_matrix(c)
(2) !call write_matrix_2d(c)
ct = c
cptr => ct(2:3,2:3)
write(*,*)
write(*,*) 'ct'
call write_matrix(ct)
(2,3)!call write_matrix_2d_ptr(ct)
write(*,*) 'cptr'
call write_matrix(cptr)
(2) !call write_matrix_2d_ptr(cptr)
end program
My third question is again related to the attached code. Overloading is not that big a deal since I can just use write_matrix_2d and write_matrix_2d_ptr separately as (2)s in the code. But, as you can see at (3), call write_matrix_2d_ptr(ct) runs fine with the target input ct while write_matrix_2d_ptr expects pointer input. Is this okay, or should I make another write_matrix_2d_target?
Thank you.
The compiler documentation is wrong (or badly out of date). A dummy argument that is a pointer can also have the intent attribute. The attribute applies to the pointer association status of the argument, not the target.
Procedures in a generic interface can be overloaded if their dummy arguments are distinguishable. Dummy arguments are distinguishable if they have different type, kind or rank. Whether something is a pointer or not is not part of its type. (To be complete, arguments are also distinguishable if one is a pointer without intent(in) and the other is allocatable.) The requirements for distinguishable dummy arguments for different procedures in a generic interface mean that the rules around which specific procedure a particular generic reference resolves to are very simple.
Your example of overloading would be ambiguous - it is fine to pass a(n associated) pointer actual argument to a non-pointer dummy - the actual argument designates the target of the pointer. It is also permitted to pass a non-pointer actual with the target attribute to an intent(in) pointer dummy.
Whether something is a pointer or not is completely orthogonal to whether it is an array or not.
Pointers in Fortran are primarily used to reference different things (targets) during program execution.
Dummy arguments only need to be a pointer if you need to do something inside the procedure that relates to the association status of the pointer - perhaps you want to test the association status, or associate the pointer with something else.
(1) The intent restriction is some copy and paste error or it is in some strange context I do not understand. There was such a resteiction in Fortran 90.
(2) "but I suppose this is bad practice since POINTER arguments going into subroutien write_matrix_2d which expects array input."
There is nothing bad about passing a Fortran pointer variable as an ordinary variable. The default argument passing mechanism is that the target of thee pointer is passed using the normal non-ointer mechanism. One only uses pinter dummy arguments if one has specific reasons to do so. Most often tbat means than one works with the association status inside the subroutine. There are some other uses but you need a specific reason to declare your argument as pointer, otherwise it just complicates things.
(3) target can be passed to pointer, intent(in) in Fortran 2008.

Fortran calls: advantage of passing by pointer vs passing by reference

It is my understanding that in Fortran arrays are passed by reference. So is there an advantage to passing a pointer to a large array (into a subroutine) as opposed to passing the array itself.
Could you also clarify this in the context of recursive functions. I have seen implementations where pointers are used "for efficiency", but if everything is passed by reference, then what's the benefit of pointers.
Here's an example. I have an array X (in reality lets say it's a very large array).
INTEGER :: X(:)
I can define a subrouitne that takes this array as follows:
SUBROUTINE FOO(X)
INTEGER, INTENT(IN) :: X(:)
INTEGER :: I
DO I = 1, 4
WRITE(*,*) X(I)
ENDDO
END SUBROUTINE FOO
When I call the subroutine above then the array X is not copied as fortran passes a reference to it. Now lets say I have a modified version of the subroutine:
SUBROUTINE FOO2(X)
INTEGER, POINTER, INTENT(IN) :: X(:)
INTEGER :: I
DO I = 1, 4
WRITE(*,*) X(I)
ENDDO
END SUBROUTINE FOO2
I can call FOO2 from a program as follows:
PROGRAM TEST
IMPLICIT NONE
INTEGER, TARGET :: X(5)
INTEGER, POINTER :: Y(:)
X = (/1,2,3,4,5/)
Y => X
CALL FOO2(Y)
END PROGRAM TEST
Then here's my question: is there a performance difference between the two versions of foo? Is there any useful scenario where the declaration of FOO2 might be preferable to FOO?
In this simple case there shouldn't be any real difference. Note the program is illegal, you don't have the explicit interface to FOO or FOO2, but I will assume you just ommited it for simplicity and they are in a module or internal.
Both arrays can be non-contiguous in principle, so no difference here. If that slows down the code, the contiguous attribute might help. Or assumed size or explicite size arrays too.
Your subroutine is too simple, so there is no danger of aliasing too. This is the common source of decreasing performance with pointers. There could be potential aliasing with some other argument or another variable you access by host or use association provided it has the target attribute.
The purpose of pointer arguments is actually to either allow disassociated (null()) arguments, or to allow changing of the association status in the subroutines. Your example doesn't use neither and therefore the pointer attribute is superfluous.
There is on last small difference. It is not specified in the standard what is actually passed to the subroutine at the machine code level for the pointer variables. If it is just an address (likely for scalars) it is the same as non-pointer, just the aliasing rules and the allowed usage are different. Otherwise some descriptor is passed, but any overhead should be negligible, the assumed shape arrays use a descriptor too.

Fortran DEALLOCATE

I am currently trying to code a little subroutine in Fortran to deallocate all allocated variables in memory when my program comes to an error, i.e., a failed to load file or an inexistent needed file. At this point, execution must be terminated, but not all allocatables are necessarily allocated (it depends on where on the code the error appeared), so i can't make a cleanup deallocating all of them.
My current approach is the following:
SUBROUTINE Cleanup(A)
REAL(8), ALLOCATABLE, DIMENSION(:) :: A
IF (ALLOCATED(A)) THEN
DEALLOCATE(A)
END IF
END SUBROUTINE
and call "Cleanup" for every allocatable. The problem with this is that not all my variables are dimension-1. I have up to three dimensions in some of them.
I first thought about writing 3 different subroutines for different dimensions and using overloading, but this do not seems to be very elegant.
Then it came to my mind that maybe i could pass a pointer instead the actuall argument A, but i've googled and it seems you can't deallocate a target variable trough a pointer.
Any ideas about how to do this properly?
Thanks.
My approach to this would use a combination of the following:
As of Fortran 95, all local un-saved allocatable variables that are allocated when a procedure finishes are automatically deallocated. Whether this is applicable depends on how your DLL is called, and hence whether you can actually structure things such that all your allocatables are unsaved locals.
As of Fortran 2003 (or Fortran 95 + the allocatable TR - this language level is widely supported amongst maintained Fortran compilers) allocatable actual arguments passed to INTENT(OUT) allocatable dummy arguments will be automatically deallocated before the procedure starts execution. Your Cleanup routine in the question just needs to add the declaration of the dummy argument as INTENT(OUT) and then there's no need for the IF test or DEALLOCATE. You still need to write the routine for each type and rank that you need to clean up.
Similar to the previous, allocatable components of derived type variables passed to an INTENT(OUT) dummy argument will be automatically deallocated. So you may be able to collect all your allocatable variables together as components in an object of derived type. Cleanup then simply involves passing that object to a procedure with an INTENT(OUT) dummy. INTENT(OUT) here also resets components that have default initialization back to their "default" value. Perhaps there's other cleanup that you need to manually do at this point too (close files, etc).
An alternative approach, again using derived types with all your variables as components, is to make the derived type object itself allocatable. When you need to cleanup, simply deallocate that one object - components of it will be automatically deallocated. Fortran 2003 allows for a final procedure to be triggered from this sort of event if you have additional other cleanup to do at this point.
A derived type approach also makes it easy to have multiple instances of whatever your DLL supports independently active at the one time (you just have multiple objects of derived type).
Examples of the derived type approach, given:
TYPE MyType
REAL, ALLOCATABLE :: variable_one(:)
INTEGER, ALLOCATABLE :: variable_two(:)
...
END TYPE MyType
INTENT(OUT) dummy
TYPE(MyType) :: object
ALLOCATE(object%variable_one(xxx))
ALLOCATE(object%variable_two(yyy))
...
IF (things_have_gone_wrong) CALL Cleanup(object)
...
SUBROUTINE Cleanup(arg)
TYPE(MyType), INTENT(OUT) :: arg
END SUBROUTINE Cleanup
ALLOCATABLE object.
TYPE(MyType), ALLOCATABLE :: object
ALLOCATE(object)
ALLOCATE(object%variable_one(...))
ALLOCATE(object%variable_two(...))
...
IF (things_have_gone_wrong) DEALLOCATE(object)

Set array's rank at runtime

I have written a program which reads a file containing multidimensional data (most commonly 3D, but 2D could occur as well). To heighten simplicity I would like to store the data in an array of the same rank (or something pretending to be one), i.e. using a three-dimensional array for 3D data, etc.; the trouble is that the program only learns about the dimensionality on reading the data file.
Currently I store all data in an array of rank one and calculate each element's index in that array from the element's coordinates (this was also suggested here). However, I have also read about pointer rank remapping, which seems very elegant and just what I have been looking for, as it would allow me to scrap my procedures for array index determination (which are probably far less efficient than what goes on behind the scenes). Now, however, it looks like I'm facing the same problem as with directly declaring a multidimensional array - how to do the declaration? Again, it requires information about the rank.
How could I use pointer rank remapping or some other, more suitable technique for setting an array's rank at runtime - in case this can be done at all. Or am I best off sticking to the rank one-array that I am currently using?
I once asked something similar, i.e. how to treat a two-dimensional array as one dimension, see here: changing array dimensions in fortran.
The answers were about the RESHAPE instrinsic of pointers, however there seems to be no way to use the same array name unless you use subroutine wrappers, but then you need callbacks to have the eventual subroutine with only one name, so the problems get larger.
program test
real, allocatable :: data(:)
allocate(data(n_data))
! read stuff, set is_2d and sizes
if (is_2d) then
call my_sub2(data, nX, nY)
else
call my_sub3(data, nX, nY, nZ)
end if
end program test
subroutine my_sub2(data, nX, nY)
real :: data(nx,nY)
! ...
end subroutine my_sub2
subroutine my_sub3(data, nX, nY, nZ)
real :: data(nx,nY,nZ)
! ...
end subroutine my_sub3
EDIT: as an alternative, set the third rank to 1:
program test
real, allocatable, target:: data(:)
real, pointer:: my_array(:,:,:)
logical is_2d
n_data = 100
allocate(data(n_data))
! read stuff, determine is_2d and n
if (is_2d) then
i=n
j=n
k=1
else
i=n
j=n
k=n
end if
my_array(1:i,1:j,1:k) => data
write(*,*) my_array
end program test
Then you handle the 2D case as a special 3D case with third dimension 1.
EDIT2: also, beware when passing non-contiguous arrays to subroutines with explicit-shape arrays: http://software.intel.com/sites/products/documentation/hpc/compilerpro/en-us/fortran/lin/compiler_f/optaps/fortran/optaps_prg_arrs_f.htm
If I understand correctly, you read in data in and 1-D array and want to assign it to 2D or 3D arrays, which you know only after reading the file. Why not declare both 2D and 3D arrays as allocatable arrays, and allocate only one of them base on your data shape? You could use the intrinsic function RESHAPE to do this conveniently.
REAL,DIMENSION(:,:), ALLOCATABLE :: arr2d
REAL,DIMENSION(:,:,:),ALLOCATABLE :: arr3d
...
! Read data into 1-D array, arr1d;
...
IF(L2d)THEN
ALLOCATE(arr2d(im,jm))
arr2d=RESHAPE(arr1d,(/im,jm/))
ELSEIF(L3d)THEN
ALLOCATE(arr3d(im,jm,km))
arr3d=RESHAPE(arr1d,(/im,jm,km/))
ENDIF
You could use the EQUIVALENCE statement like this:
Program ranks
integer a_1d(12)
integer a_2d(2, 6)
integer a_3d(2, 2, 3)
equivalence (a_1d, a_2d, a_3d)
! fill array 1d
a_1d = (/1,2,3,4,5,6,7,8,9,10,11,12/)
print *, a_1d
print *, a_2d(1,1:6)
print *, a_2d(2,1:6)
print *, a_3d(1,1,1:3)
print *, a_3d(2,1,1:3)
print *, a_3d(1,2,1:3)
print *, a_3d(2,2,1:3)
end program ranks
You can write a subroutine for different ranks of array and create an interface
Here in example I have shown that how to populate an array of different array using interface statement `
program main
use data
implicit none
real,dimension(:,:,:),allocatable::data
integer::nx,ny,nz
nx = 5
ny = 10
nz = 7
call populate(nx,ny,nz,data)
print *,data
end program main `
data module is here
module data
private
public::populate
interface populate
module procedure populate_1d
module procedure populate_2d
module procedure populate_3d
end interface
contains
subroutine populate_1d(x,data)
implicit none
integer,intent(in)::x
real,dimension(:),allocatable,intent(out):: data
allocate(data(x))
data=rand()
end subroutine populate_1d
subroutine populate_2d(x,y,data)
implicit none
integer,intent(in)::x,y
real,dimension(:,:),allocatable,intent(out):: data
allocate(data(x,y))
data=rand()
end subroutine populate_2d
subroutine populate_3d(x,y,z,data)
implicit none
integer,intent(in)::x,y,z
real,dimension(:,:,:),allocatable,intent(out):: data
allocate(data(x,y,z))
data=rand()
end subroutine populate_3d
end module data
There is an interface to populate 1d, 2d and 3d arrays. you can call populate interface instead of calling individual subroutines. It will automatically pick the relevant one.

pointer as a dummy argument

I am somewhat puzzled by the following program
module test
implicit none
type TestType
integer :: i
end type
contains
subroutine foo(test)
type (TestType), intent(out) :: test
test%i = 5
end subroutine
subroutine bar(test)
type (TestType), intent(out) :: test
test%i = 6
end subroutine
end module
program hello
use test
type(TestType) :: t
call foo(t)
print *, t%i
call bar(t)
print *, t%i
end program hello
and its derivatives. More on those later. As we know, Fortran transfers routine arguments as a pass-by-reference, meaning that the entity emerging at the dummy argument test for both foo and bar is the same memory space granted on the stack in program hello. So far so good.
Suppose I define in program hello the type(TestType) :: t as a pointer, and allocate it.
program hello
use test
type(TestType), pointer :: t
allocate(t)
call foo(t)
print *, t%i
call bar(t)
print *, t%i
deallocate(t)
end program hello
The code works as before, the only difference being that the object was not allocated on the stack, but on the heap.
Now assume to go back to the stack-allocated program and that subroutine bar is instead defined as
subroutine bar(test)
type (TestType), pointer :: test
test%i = 6
end subroutine
The program does not compile anymore because you must use the heap-allocated version to make it work, or to be more accurate it is mandatory to pass a pointer to the routine when the routine is defined to accept a pointer as a dummy argument. On the other hand, if the dummy argument does not contain the pointer keyword, the routine would accept both pointers and non-pointers.
This makes me wonder... what's the point of declaring a dummy argument a pointer ?
Reposted from comp.lang.fortran, an answer by Tobias Burns:
Now assume to go back to the stack-allocated program and that
subroutine bar is instead defined as
subroutine bar(test)
type (TestType), pointer :: test
test%i = 6
end subroutine
The program does not compile anymore because you must use the
heap-allocated version to make it work,
That's not quite correct: You can also not pass an ALLOCATABLE variable
to a dummy with POINTER attribute. I think one (practical) reason is
that the pointer address can escape and you would thus cause alias
problems. A formal reason is that an ALLOCATABLE is simply not a
POINTER; additionally, the standard does not talk about heap vs. stack
vs. static memory. And in fact, local arrays [with constant bounds] will
often be created in static memory and not on the stack (unless you use
OpenMP or the RECURSIVE attribute). Thus, your "stack" example could
also be a "static memory" example, depending on the compiler and the
used options.
or to be more accurate it is
mandatory to pass a pointer to the routine when the routine is defined
to accept a pointer as a dummy argument.
That's also not completely true. In Fortran 2008 you can pass a
non-POINTER, which has the TARGET attribute, to a pointer dummy which
has the INTENT(IN) attribute. (Pointer intent is relative to the pointer
association status; for non-pointer dummies the intents are about the
value stored in the variable.)
This makes me wonder... what's the point of declaring a dummy argument
a pointer ?
Well, if the argument has the POINTER attribute, you can allocate and
free the pointer target, you can associate the pointer with some target
etc. Up to Fortran 95 it was not possible to have ALLOCATABLE dummy
arguments thus a pointer had to be used if a (dummy) argument had to be
allocated in a procedure.
If you can, you should try to use rather ALLOCATABLEs than POINTERs -
they are easier to use, do not leak memory and have pose no
alias-analysis problems to the compiler. On the other hand, if you want
to create, e.g., a linked list, you need a pointer. (Though, for a heap
usage, also Fortran 2008's allocatable components could be used.*)
*I mean:
type t
type(t), allocatable :: next
end type
where the component is of the same type as the type being defined;
before F2008 this was only allowed for pointers but not for allocatables.
and by R. Maine
As we know, Fortran transfers routine arguments as a
pass-by-reference,
We apparently know incorectly, then. The standard never specifies that
and, indeed goes quite a lot out of its way to avoid such specification.
Although yours is a common misconception, it was not strictly accurate
even in most older compilers, particularly with optimization turned on.
A strict pass-by-reference would kill many common optimizations.
With recent standards, pass-by-reference is all but disallowed in some
cases. The standard doesn't use those words in its normative text, but
there are things that would be impractical to implement with
pass-by-reference.
When you start getting into things like pointers, the error of assuming
that everything is pass-by-reference will start making itself more
evident than before. You'll have to drop that misconception or many
things wil confuse you.
I think other people have answered the rest of the post adequately. Some
also addressed the above point, but I wanted to emphasize it.
Hope this answers your question.

Resources