I need in a program to pass some allocatable arrays to subroutines, and i need to know if the way I do it are in the standard or not.
If you know where I can search for the standard of fortran, Tell me please.
Here is a little code that will better explain than words
program test
use modt99
implicit none
real(pr), dimension(:), allocatable :: vx
allocate(vx(-1:6))
vx=(/666,214,558,332,-521,-999,120,55/)
call test3(vx,vx,vx)
deallocate(vx)
end program test
with the module modt99
module modt99
contains
subroutine test3(v1,v2,v3)
real(pr), dimension(:), intent(in) :: v1
real(pr), dimension(0:), intent(in) :: v2
real(pr), dimension(:), allocatable, intent(in) :: v3
print*,'================================'
print*,v1(1:3)
print*,'================================'
print*,v2(1:3)
print*,'================================'
print*,v3(1:3)
print*,'================================'
end subroutine test3
end module modt99
on screen, I get
================================
666.000000000000 214.000000000000 558.000000000000
================================
214.000000000000 558.000000000000 332.000000000000
================================
558.000000000000 332.000000000000 -521.000000000000
================================
So are the three ways of dummy arguments in subroutine test3 legal (in what version of fortran, 90, 95, 2003?) and are their behavior normal?
The first version passes the array slice to the subroutine. Note that boundary information are not passed along in this way, arrays are assumed to start at 1 and go to size(array).
The second way is just like the first one, but you manually set the lower boundary to 0, that's why printing v3(1:3) gives you the values with an offset of 1.
The third way passes all array information to the subroutine (including boundaries), hence the "correct" indexing. Passing allocatable arrays was introduced with Fortran 2003.
Apart from the fact that you have an aliasing issue (passing the same variable to three different dummy arguments), all three versions are legal.
You can find all documents of the standards here.
Especially, take a look at the Fortran 2003 Standard, Ch. 5.1.2.5 DIMENSION attribute to see the differences between assumed shape and deferred shape arrays in dummy arguments.
Related
In a rather old style Fortran project, I often see this pattern, when an array is passed by its first item:
program test
implicit none
integer :: a(10)
a(:) = 1
call sub(a(1), 10) ! here
contains
subroutine sub(a, length)
integer, intent(in) :: length
integer, intent(in) :: a(length)
print *, a
end subroutine
end program
where it could be:
call sub(a, 10) ! here
which is valid even in Fortran 77.
Note the size of the array has to be passed and used explicitly, this will not work for assumed shape array:
subroutine sub(a)
integer, intent(in) :: a(:)
print *, a
end subroutine
For me this is confusing, as the call suggests a scalar is passed to the subroutine. I suppose it works because the array is passed by reference.
Is there any reason to pass arrays like this, especially now?
One uses this feature when using the older interface to the non-blocking MPI routines.
Say you want to pass subarray A(10,10:19) which is a part of a bigger array A(1:100,1:100).
If you pass
use mpi
call ISend(A(10,10:19), 10, MPI_REAL, ...
you pass a temporary copy of array A and the address of the temporary copy will not be valid at the time of the MPI_Wait. Therefore, instead, you create an MPI derived type, that describes the offsets in the array to be sent and you use it as
use mpi
call ISend(A(10,10), 1, derived_type, ...
Of course, with the most modern MPI libraries and compilers you use use mpi_f08. However, most HPC codes in the wild do not use it yet.
Another solution is to use an MPI derived type that includes the absolute address of the subarray and just pass A. Sometimes it is practical, sometimes it is not. It depends on how much the subarrays passed vary throughout the code.
Be aware that there are other issues present in non-blocking MPI in the old interface and it helps if you explicitly mark the routines as ASYNCHRONOUS.
Consider the following example:
implicit none
integer a(2,2)
a = RESHAPE([1,2,3,4],[2,2])
call sub(a(2,1))
print '(2I3)', TRANSPOSE(a)
contains
subroutine sub(b)
integer, intent(out) :: b(2)
b = -1
end subroutine sub
end
Here, the element sequence represented by the actual argument a is a(2,1), a(1,2), a(2,2), and the first two are associated with the dummy argument b.
For arrays of rank greater than one, this element sequence use may make things (much) easier to specify certain consecutive elements of the actual argument. For a rank-1 array we can write a(3:) instead of a(3), say, as the actual argument. For higher rank arrays we haven't that option.
I won't express an opinion on whether this is a good use this feature.
I am writing code to add on a closed-source Finite-Element Framework that forces me (due to relying on some old F77 style approaches) in one place to rely on assumed-size arrays.
Is it possible to write an assumed-size array to the standard output, whatever its size may be?
This is not working:
module fun
implicit none
contains
subroutine writer(a)
integer, dimension(*), intent(in) :: a
write(*,*) a
end subroutine writer
end module fun
program test
use fun
implicit none
integer, dimension(2) :: a
a(1) = 1
a(2) = 2
call writer(a)
end program test
With the Intel Fortran compiler throwing
error #6364: The upper bound shall not be omitted in the last dimension of a reference to an assumed size array.
The compiler does not know how large an assumed-size array is. It has only the address of the first element. You are responsible to tell how large it is.
write(*,*) a(1:n)
Equivalently you can use an explicit-size array
integer, intent(in) :: a(n)
and then you can do
write(*,*) a
An assumed-size array may not occur as a whole array reference when that reference requires the shape of the array. As an output item in a write statement that is one such disallowed case.
So, in that sense the answer is: no, it is not possible to have the write statement as you have it.
From an assumed-size array, array sections and array elements may appear:
write (*,*) a(1:2)
write (*,*) a(1), a(2)
write (*,*) (a(i), i=1,2)
leading simply to how to get the value 2 into the subroutine; at other times it may be 7 required. Let's call it n.
Naturally, changing the subroutine is tempting:
subroutine writer (a,n)
integer n
integer a(n) ! or still a(*)
end subroutine
or even
subroutine writer (a)
integer a(:)
end subroutine
One often hasn't a choice, alas, in particular when associating a procedure with a dummy procedure with a specific interface . However, n can get into the subroutine through any of several other ways: as a module or host entity, or through a common block (avoid this one if possible). These methods do not require modifying the interface of the procedure. For example:
subroutine writer(a)
use aux_params, only : n
integer, dimension(*), intent(in) :: a
write(*,*) a(1:n)
end subroutine writer
or we could have n as an entity in the module fun and have it accesible in writer through host association. In either case, setting this n's value in the main program before writer is executed will be necessary.
If I want to create an allocatable multidimensional array, I can say:
program test
real, dimension(:,:), allocatable :: x
integer :: i,j
allocate(x(5, 5))
do i = 1,size(x,1)
do j = 1,size(x,2)
x(i,j) = i*j
end do
end do
write(*,*) x
end program test
However, what if I don't know how many dimension x will be. Is there a way to accommodate that?
Newer compilers allow the use of assumed-rank objects for interoperability.
I think that is what you are looking for. But this is for call to functions or subroutines. The function or subroutine declares the dummy argument as assumed-rank and the actual rank is passed with the actual argument at runtime.
Example from IBM website:
REAL :: a0
REAL :: a1(10)
REAL :: a2(10, 20)
REAL, POINTER :: a3(:,:,:)
CALL sub1(a0)
CALL sub1(a1)
CALL sub1(a2)
CALL sub1(a3)
CONTAINS
SUBROUTINE sub1(a)
REAL :: a(..)
PRINT *, RANK(a)
END
END
follow this or that for more details
It looks to me like you're trying to carry out stencil computations across an array of rank-1, -2 or -3 -- this isn't quite the same as needing arrays of arbitrary rank. And assumed-rank arrays are really only applicable when passing an array argument to a routine, there's no mechanism even in the forthcoming standard for declaring an array to have a rank determined at run-time.
If you're impatient to get on with your code and your compiler doesn't yet implement TS 29113:2012 perhaps the following approach will appeal to you.
real, dimension(:,:,:), allocatable :: voltage_field
if (nd == 1) allocate(voltage_field(nx,1,1))
if (nd == 2) allocate(voltage_field(nx,ny,1))
if (nd == 3) allocate(voltage_field(nx,ny,nz))
Your current approach faces the problem of not knowing, in advance of knowing the number of dimensions in the field, how many nearest-neighbours to consider in the stencil, so you might find yourself writing 3 versions of each stencil update. If you simply abuse a rank-3 array of size nx*1*1 to represent a 1D problem (mutatis mutandis a 2D problem) you always have 3 sets of nearest-neighbours in each stencil calculation. It's just that in the flattened dimensions the nearest neighbour is, well, either a ghost cell containing a boundary value, or the cell itself if your space wraps round.
Writing your code to work always in 3 dimensions but to make no assumptions about the extent of at least two of them will, I think, be easier than writing rank-sensitive code. But I haven't given the matter a lot of thought and I haven't really thought too much about its impact on your f-d scheme.
I'm in the process of learning fortran (90), with past experience in c and python. I'm reading about arrays (it's interesting to see that so much of the python array behavior is based on that of fortran); and I was wondering, is there ever a reason to assign an allocatable array without a deferred size? And is it possible to defer the size without using allocatable -- if so, how?
e.g.
REAL, DIMENSION(:) :: arr1
REAL, ALLOCATABLE, DIMENSION(20) :: arr2
Array terminology can be a bit daunting in Fortran. The first thing to realize is the difference between an actual argument, a variable for which a procedure has to allocate some memory, and a dummy argument, placeholders for actual arguments passed along by the calling procedure. If a variable is in a procedure's argument list, it is a dummy argument.
So, as for actual arguments, there are two kinds of arrays:
explicit-shape, e.g. <type> :: A(3,6)
deferred-shape, e.g. <type>, <allocatable|pointer> :: A(:,:,:)
A deferred shape must have an allocatable or pointer attribute.
When it comes to dummy arguments, there are also two kinds of arrays:
assumed-size, e.g. <type> :: A(4,5,*), B(1:2,4:*), C(m,n)
assumed-shape, e.g. <type> :: A(:,4:)
The actual and dummy arguments are not related in any way, so don't mix them. Also note that there exist something called automatic arrays, these look exactly like assumed-size arrays with dummy variables as sizes (C(m,n)), but don't appear in the argument list, so they are not dummy arguments.
For the assumed-size array, the last dimension's upper bound should be left unspecified (the *), other than that lower+upper bounds can be specified, including variables passed along to the procedure. Think of it as an array for which you re-specify the entire layout, irrespective of the actual argument. This allows you to do things like:
program toby
integer, parameter :: n = 10
real :: a(n**3)
call my_sub(a,n)
end program
subroutine my_sub(a,n)
integer, intent(in) :: n
real, intent(inout) :: a(n,n,*)
...
end subroutine
The other dummy argument, the assumed-shape, only allows you to specify lower bounds, as it gets its size info from the actual argument. This means you also can't redefine the dimensionality, and you need an explicit interface (e.g. via a module). This makes it more stringent, and also unnecessary to pass along size information with the array.
program toby
integer, parameter :: n = 10
real :: a(n,n,n)
call my_sub(a)
contains
subroutine my_sub(a)
real, intent(inout) :: a(:,:,:)
integer :: n
n = size(a,1)
...
end subroutine
end program
You can read about it in much more detail here I find it to be an ideal reference.
Last but not least, since you mention python, don't be to eager to apply python-like array slicing in Fortran, as it can cause the use of temporary arrays, which can slow down the program. You can use -fcheck=array-temps with gfortran to warn for that. Furthermore, even though elemental operations on whole arrays are recommended for efficiency (e.g. A=A+1 in using arrays efficiently), don't misinterpret that as "writing very concise code is good for efficiency". The latter is of course not (necessarily) true.
Is it indeed possible to allocate multiple shared arrays in CUDA Fortran without having to resort to having just one shared array and using index offsetting?
Pointers don't work, the 'pointer' and 'target' attributes conflict with the 'shared' attribute.
This is what I want to acheive:
attributes(global) subroutine shared_sub_arrays()
integer :: i
real, shared, dimension(*), target :: alldata
real, shared, dimension(:), pointer :: left
real, shared, dimension(:), pointer :: centre
real, shared, dimension(:), pointer :: right
i = threadIdx%x
left => alldata(1:3)
centre => alldata(4:6)
right => alldata(7:9)
left(i) = 1.0
centre(i) = 2.0
right(i) = 3.0
end subroutine shared_sub_arrays
Does anyone know of another way to do this?
Thanks in advance for the help
From the Portland CUDA Fortran manual:
These rules apply to device data:
Device variables and arrays may not have the Pointer or Target attributes.
So I guess that's just not possible. As for other ways to do it, you could manually keep track of the indices (which seems you don't want to do), or use a matrix with 3 columns, e.g.
real, shared, dimension(:,:) :: alldata
allocate(data(N,3))
! name indices
left=1
centre=2
right=3
! access the columns
alldata(i,left)
alldata(i,centre)
alldata(i,right)