In fortran, is it safe to assume that the status of an unallocated array is .not.allocated and that the status of an allocatable array is retained between calls if it is declared with the save attribute? In other words, barring minor output formatting differences, is it safe to assume that the following program will always result in the output:
First time here
Been here before
test program:
program main
call sub()
call sub()
end program main
subroutine sub()
real,save,allocatable,dimension(:) :: a
if(.not. allocated(a))then
print*,"First time here"
allocate(a(10))
else
print*,"Been here before"
endif
end subroutine sub
I ask mainly because I know that you can't assume a pointer's default association is .not.associated
Yes!
And now I discover you need 30 characters...
Yes, this is one of the nice things with Fortrans allocatable arrays. But, if for some reasons, you had to use pointers, you could achive a similar effect by:
program main
call sub()
call sub()
end program main
subroutine sub()
real, pointer, dimension(:), save :: a => null()
if(.not. associated(a))then
print*,"First time here"
allocate(a(10))
else
print*,"Been here before"
endif
end subroutine sub
The save attribute is optional here, as the assignment in the variable declaration implies this any way.
Related
I am reading from a file that contains a value, T, which will be used to initialize several arrays that will take T as the first dimension with allocate later. i.e.
subroutine read_file(T,F,array,A,B,C,...)
...
real, intent(out) :: T,F
real, intent(in) :: A,B,C
real, intent(out) :: array
...
read(1,*) T
...
read(1,*) F
...
read(1,*) array(1), array(5), array(6)
read(1,*) array(2), array(4)
read(1,*) array(3)
...
if (F.eq.1) then
array(1) = A(1)
array(2) = B(2)
array(3) = C(3)
endif
...
program main
...
do I=1,nproc
...
do J=1,nsteps
...
call read_file(T,F,array,A,B,C,...)
...
enddo
...
if (F.eq.1.and.etc.) then
...
allocate(A(T,3))
allocate(B(T,6))
allocate(C(T))
...
endif
...
enddo
The read statement is contained in a read_file subroutine in a module in modules.for. The allocate statements are in main.for where read_file is also called.
Subroutine read_file also reads many other things and it is called many times over the course of 1 execution of the code where some files may have T be zero.
I need to pass in A, B, and C into read_file. Depending on the condition of a flag, F, also being read in read_file, the values in A, B, and C need to be assigned to array(1,6) that would otherwise be read directly from the file.
So I guess my question is: How do I pass in arrays that may not have been allocated in size? I have written checks in the code to make sure A, B, and C will not be actually used unless they went through allocation with a known size given as user input T, but the compiler has been giving me issues.
I tried compile the code and intel compiler first returned the error saying the types for A,B,C are not declared in read_file, so I declared them using T and real :: A(T,3) in read_file. Then it said since T is a intent(out), it cannot be used to give dimension to A, B, and C since they are intent(in). So I removed the intent(out) from T (as in it is just real :: T now).
And now, the error says:
If the actual argument is scalar, the dummy argument shall be scalar
unless the actual argument is of type character or is an element of an
array that is not assumed shape, pointer, or polymorphic.
I edited my question to provide more code and clarify my question.
Thanks to the people who answered and commented, I now know that I can declare a variable as allocatable in the subroutine, which should solve my problem.
Thanks!
Jesse
It seems like the safest way to deal with the problem you describe is to let read_file handle the allocation, that is, pass A,B,C to read_file as
real, intent(inout), allocatable :: A(:,:), B(:,:), C(:,:)
With intent(inout) allowing you to call read_file multiple times with the same A,B,C without losing the information from previous calls. If that is not required, feel free to use just intent(out). Passing unallocated arrays as arguments is fine, just make sure to have the allocation happen before any access is attempted.
You can then allocate A,B,C inside read_file, after T has been read in.
If tempering with read_file is not possible, or you want to have the allocation to happen in main, you can also use the approach you described. First, allocate A,B,C as dummy arrays
allocate(A(0,0), B(0,0), C(0,0))
which you can pass to the first call of read_file (0-sized arrays are allowed, just make sure you do not try to access their entries). If I understood correctly, the first call will not perform any operations on A,B,C and they are only required to be allocated in subsequent calls to read_file. If that is the case, allocating in main.for also works.
Once you obtained T, you can reallocate A,B,C with
if(allocated(A)) deallocate(A)
allocate(A(T,3))
You can then pass the reallocated arrays to the next call of read_file.
What are the recommendations or best practices regarding where should we allocate an array?
For instance, if I have a (simplified version of my) program as shown, I am allocating the output variable (the variable of interest) in the main program. This main program calls subroutine foo, which, in turn, calls subroutine foo2, who does the actual calculations.
My question is what is the best/recommended practice to where the allocation should be done.
If foo2 does the actual calculation, should it allocate the arrays?
If foo calls foo2, should foo allocate the array and foo2 do
just the calculations?
Should I write a new function/subroutine to just allocate the arrays?
Or is it best to allocate on the main program and pass the arrays as
assumed-shape?
If it is important, I have a module called global, that contains the derived types on main program, and the main parameters of the code, such as the size of each array (Ni, Nj, tolerances etc)
program main
use global
implicit none
type(myVar_) :: ans
Ni = 10
Nj = 20
if (allocated(ans%P)) deallocate(ans%P)
allocate(ans%P(1:Ni, 1:Nj))
call foo(ans)
print *, P
end program main
module global
integer, parameter :: dp=kind(0.d0)
integer :: Ni, Nj
type myVar_
real(dp), allocatable :: P(:,:)
end type myVar_
end module global
subroutine foo(myVar)
use global
implicit none
type(myVar_) :: myVar
call foo2(myVar%P)
end subroutine
subroutine foo2(P)
use global
implicit none
real(dp), intent(inout) :: P(:,:)
! do calculations for P
end subroutine foo2
what is
It is indeed good practice to avoid allocation in low-level subroutines and function for performance reason. As you can see from [1], simple additions take about 1-3 CPU cycles, an allocation and deallocation pair (of a "small" array) can take between 200-500 CPU cycles.
I would suggest you to write a subroutine using a "work" variable as input and possibly operating in place (i.e. overriding the input with the result), e.g.
subroutine do_computation(input,output,work1,work2)
work1 = ...
work2 = ...
output = ...
end subroutine
An you could make a wrapper function which makes the allocation for convenience:
subroutine convenient_subroutine(input,output)
allocate(work1(...),work2(...)
call do_computation(input,output,work1,work2)
deallocate(work1,work2)
end subroutine
When performance is not critical, you can call the convenient_subroutine, but otherwise you call do_computation trying to share the work arrays between loop iteration and between different other subroutines.
[1] http://ithare.com/infographics-operation-costs-in-cpu-clock-cycles/
My question is about array allocation in Fortran.
I have a subroutine, say readParams, where I want to read some dynamically sized arrays from files. These are also used outside the subroutine.
What is the best way to handle this?
In F95 it seems to be impossible to allocate within the subroutine and pass the arrays, filled with values, back to the main program.
But if I allocate it in the main program and use "intent(inout)" in the subroutine it also gets deallocated there.
(I'm using F90/95 here, but since the code is not large I could also modify it to a newer version... I'm rather new to Fortran, so I'm unsure if an improvement of array handling is worthwhile the time investment^^
EDIT Thanks for the hint. I am not trying to deallocate my arrays within a subroutine though.
The problem is: I have an array which I need to allocate somewhere within my main program. The arraysize is known only after I read it from an input in subroutine readArgs. Therefore I make the array "allocatable". Once allocated that status must never change again.
The array is filled with values in a subroutine readParams.
Do I allocate it best in main or in readParams and how?
... I have now put my subroutines in a module and use them from there.
At the moment I do the allocation in main, pass the arrays to my subroutine and have removed the "allocatable" statement in the array declaration in the subroutine.
It seems to work but I still don't really understand if this is the way to go.
In my opinion the question is an exact duplicate of Can a input argument of a Fortran subroutine be deallocated and allocated in the body of the subroutine? and if it
is not, then it should be closed because you did not show any code so how can we tell you whether your code (that works) is correct???
But I am alone with this opinion against many, so if your code looks similar to this it is probably correct:
You can either read the size in a subroutine and allocate it in the main program:
module subs
contains
subroutine readArgs(n)
integer, intent(out) :: n
!read n here
end subroutine
subroutine readParams(a)
real :: a(:)
do i = 1, size(a)
!read values of a
a(i) =
end do
end subroutine
end module
program main
use subs
integer :: n
readArgs(n)
allocate(a(n))
readParams(n)
end program
Or you can allocate it in the subroutine. You must fulfil all the requirements in Can a input argument of a Fortran subroutine be deallocated and allocated in the body of the subroutine?
module subs
contains
subroutine readArgs(n)
integer, intent(out) :: n
!read n here
end subroutine
subroutine readParams(n, a)
real, allocatable :: a(:)
allocate(a(n))
do i = 1, size(a)
!read values of a
a(i) =
end do
end subroutine
end module
program main
use subs
integer :: n
readArgs(n)
readParams(n)
end program
It doesn't matter what you do, both approaches are pefectly fine.
If anyone is still interested I'm using the Cuda compiler pgf90 and the following works:
module subs
implicit none
contains
subroutine load_array( b )
real, allocatable :: b(:)
allocate( b(10) )
b( 7 ) = 4
end subroutine load_array
end module subs
Program main
use subs
implicit none
real, allocatable :: a(:)
Call load_array( a )
print *, a(7)
deallocate( a )
end program main
I'm making a CFD program which uses arrays. In the final part of the code, shown below, I have the subroutine INIT which will put the variable temperature at the value 0. The temperature is a two dimensional array declared in the main program.
The problem is that when I call the subroutine INIT it doesn't know that I already declared the array T(NN,NN). In other words, the array is not detected in the subroutine.
How can I fix this? How can I set T(NN,NN) as like a global variable?
! VARIABLES
PARAMETER (NN=100)
DIMENSION X(NN),Y(NN),DXPW(NN),DXEP(NN),DYNP(NN),DYPS(NN),SEW(NN),SNS(NN),T(NN,NN)
...
WRITE(*,*)
SNS(1)=0.0
SNS(NJ)=0.0
DO J=2,NJM1
SNS(J)=0.5*(DYNP(J)+DYPS(J))
WRITE(*,*)SNS(J)
END DO
CALL INIT(NI,NJ)
END
SUBROUTINE INIT(NI,NJ)
DO I=1,NI
DO J=1,NJ
!T(I,J)=0.0
END DO
END DO
RETURN
END SUBROUTINE
I am looking for a way to address a body of character information with two concurrent arrays in the same program unit.
For example, I want
CHARACTER(1) Array1(40960)
and
CHARACTER(4096) Array2(10)
pointing to the same body of information.
Note I have been careful in this example that the product of the dimensions and rank of the arrays are the same.
I want the solution to be allocatable, so I don't think EQUIVALENCE or COMMON would work.
Any ideas?
Something like this:
use, intrinsic :: iso_c_binding
...
character, dimension(40960), target :: array1
character(4096), dimension(:), pointer :: array2
...
call c_f_pointer (c_loc(array1), array2, [10])
Now, array2 points to the same storage as array1. You can make array1 allocatable if you want - in the call to c_f_pointer, the last argument is an array constructor with the dimension information for the newly assigned pointer. Don't forget the TARGET attribute on array1.
If, for some delightfully obscure and unlikely reason, your compiler's default character kind is not the same as its C character kind, then you can also use sequence association to accomplish the same outcome as via C pointer games. For example:
PROGRAM len_remapping
IMPLICIT NONE
CHARACTER, ALLOCATABLE, TARGET :: array1(:)
CHARACTER(10), POINTER :: array2(:)
INTEGER :: i
ALLOCATE(array1(40))
array1 = [(ACHAR(i+'A'-1), i = 1, 40)]
CALL associate_the_pointer( &
array1, SIZE(array1) * LEN(array1), &
array2, LEN(array2) )
PRINT "(*(A,:,1X))", array1
PRINT "(*(A,:,1X))", array2
PRINT *, LEN(array2), SIZE(array2)
CONTAINS
SUBROUTINE associate_the_pointer(targ, elements, ptr, ptr_length)
INTEGER, INTENT(IN) :: elements, ptr_length
CHARACTER(ptr_length), INTENT(IN), TARGET :: targ(elements / ptr_length)
CHARACTER(ptr_length), INTENT(OUT), POINTER :: ptr(:)
ptr => targ
END SUBROUTINE associate_the_pointer
END PROGRAM len_remapping
This approach has the benefit of requiring you to read some parts of the Fortran standard fifteen times over to make sure that it is conforming, and not much else.