NickFort
Technical User
- Jun 10, 2010
- 113
Hi all,
I'm sure this is obvious to many of you, but it wasn't to me! I just had a little revelation regarding variable-length arrays as the output of subroutines/functions, and I have to share this with those of you who don't know, because I can't contain my excitement.
I was just sitting here wondering how one would have a variable-length array (vector in my case) as an output to a function. I knew allocatable arrays could be allocated to different sizes, but what I didn't know was that if the dummy argument of a subroutine was allocatable and allocated within the subroutine, the argument of the actual procedure call (which also has the "allocatable" attribute) gets allocated accordingly.
Now, I don't recall reading this in any of the Fortran books I've read, but I must admit that I tend to skip to relevant sections and skim over others. I'd been wondering for aaaaaages how it could be done, and I decided to play around today, expecting the worst. This post is here for the benefit of those who -- like me before about 20 minutes ago -- don't know how to do it.
To this demonstrate how this works is the code below. It simply generates a random-length vector, whose elements are random reals, sends it to the driver program, prints the result, and finishes. It works on gfortran, but not on g95 (which doesn't seem to have a working "system_clock" feature to generate the "random" seed). If you want to use in with g95, you'll have to use a different method for the random seed.
--------------------------------------
Background: Chemical engineer, familiar mostly with MATLAB, but now branching out into real programming.
I'm sure this is obvious to many of you, but it wasn't to me! I just had a little revelation regarding variable-length arrays as the output of subroutines/functions, and I have to share this with those of you who don't know, because I can't contain my excitement.
I was just sitting here wondering how one would have a variable-length array (vector in my case) as an output to a function. I knew allocatable arrays could be allocated to different sizes, but what I didn't know was that if the dummy argument of a subroutine was allocatable and allocated within the subroutine, the argument of the actual procedure call (which also has the "allocatable" attribute) gets allocated accordingly.
Now, I don't recall reading this in any of the Fortran books I've read, but I must admit that I tend to skip to relevant sections and skim over others. I'd been wondering for aaaaaages how it could be done, and I decided to play around today, expecting the worst. This post is here for the benefit of those who -- like me before about 20 minutes ago -- don't know how to do it.
To this demonstrate how this works is the code below. It simply generates a random-length vector, whose elements are random reals, sends it to the driver program, prints the result, and finishes. It works on gfortran, but not on g95 (which doesn't seem to have a working "system_clock" feature to generate the "random" seed). If you want to use in with g95, you'll have to use a different method for the random seed.
Code:
program var_length
implicit none
interface
subroutine random_vector(vector)
implicit none
real, dimension(:), allocatable, intent(out) :: vector
end subroutine
end interface
integer :: length_call,k
real, dimension(:), allocatable :: vector_call
call random_vector(vector_call)
length_call = size(vector_call)
print *, "length_call: ", length_call
do k=1,size(vector_call)
print *, vector_call(k)
end do
deallocate(vector_call)
end program var_length
!==============================================
subroutine random_vector(vector)
implicit none
real, dimension(:), allocatable, intent(out) :: vector
integer :: length
real :: length_real
if (allocated(vector)) deallocate(vector)
call init_random_seed()
call random_number(length_real)
length = int(length_real*10)+1
allocate (vector(length))
call random_number(vector)
end subroutine random_vector
!==============================================
subroutine init_random_seed()
integer :: i, n, clock
integer, dimension(:), allocatable :: seed
call random_seed(size = n)
allocate(seed(n))
call system_clock(count=clock)
seed = clock + 37 * (/ (i - 1, i = 1, n) /)
call random_seed(put = seed)
deallocate(seed)
end subroutine
--------------------------------------
Background: Chemical engineer, familiar mostly with MATLAB, but now branching out into real programming.