cirnelle
cirnelle

Reputation: 59

Create array containing other declared variables in Fortran

I would like to create an array containing variables that have already been declared, so that I can loop through this array to access the elements by its index and carry out some operation. In Python, this would be easy. Say I want to create a target_array:

a = [3,4]
b = [5,6]

target_array = [a,b]

for ta in target_array:

    # some operation here

However, I am not sure how can I do this in Fortran. I tried the following:

real, dimension(2,2,2) :: a
real, dimension(2,2,2) :: b

real, parameter :: target_array = [a,b]
integer :: i
real, dimension(2,2,2) :: target_var

do i = 1,SIZE(target_array)
   
   target_var = target_array(i)

   ...

end do

However, I received the following error for the line where i declare target_array:

This symbol must be a defined parameter, an enumerator, or an argument of an inquiry function that evaluates to a compile-time constant.   [a]

Can someone help? Thank you!

Upvotes: 1

Views: 303

Answers (3)

roygvib
roygvib

Reputation: 7395

FWIW, this is an array-pointer version of BenBoulderite's code

program main
    implicit none
    integer i
    real, allocatable, target :: a(:), b(:)

    type ArrayPtr
        real, pointer :: ptr(:)
    endtype
    type(ArrayPtr), allocatable :: arrays(:)

    a = [1, 2]
    b = [3, 4, 5]

    arrays = [ArrayPtr(a), ArrayPtr(b)]

    b(:) = b(:) + 100

    do i = 1, size(arrays)
        print *, i, " : ", arrays(i) % ptr
    enddo
end

!! gfortran-10 test.f90 && ./a.out
       1  :    1.00000000   2.00000000    
       2  :    103.000000   104.000000   105.000000  

Here, arrays shares data with a and b, so the modification of the latter affects the contents of arrays. Because allocatable arrays (like a) are automatically deallocated at the end of subroutines etc, we need to make sure that the original arrays (like a) are kept alive when using arrays as array views.

The allocatable-array version below does not have this pitfall, but arrays have different data from a and b, so the modification of the latter does not affect arrays (like b below).

program main
    implicit none
    integer i
    real, allocatable, target :: a(:), b(:)

    type ArrayVal
        real, allocatable :: dat(:)
    endtype
    type(ArrayVal), allocatable :: arrays(:)

    a = [1, 2]
    b = [3, 4, 5]

    arrays = [ArrayVal(a), ArrayVal(b)]

    b(:) = b(:) + 100

    do i = 1, size(arrays)
        print *, i, " : ", arrays(i) % dat
    enddo
end
!! gfortran-10 test.f90 && ./a.out
       1  :    1.00000000   2.00000000    
       2  :    3.00000000   4.00000000   5.00000000 

Upvotes: 1

BenBoulderite
BenBoulderite

Reputation: 336

Derived types could help you here.

You could first define a derived type (let us call it myVar_T) that fits to what you describe as "variables that have already been declared". Then, you define the target_array variable as an array of type myVar_T.

Supposing that you want to work with rank 1 arrays of real numbers (as in the code snippet you posted), below is an example that compiles and runs. The strength of this method is that you can adapt it to variables that would be much more complex than small arrays of numbers.

program array_of_vars

implicit none

type :: myVar_T
  real, dimension(2) :: arr
end type

type(myVar_T), allocatable :: target_array(:)
real, dimension(2) :: target_val
integer :: target_array_length
integer :: iTarget
real :: mySum

target_array_length = 3
allocate(target_array( target_array_length ))

target_array(1)%arr = [3,4]
target_array(2)%arr = [5,6]
target_array(3)%arr = [7,8]

do iTarget = 1, target_array_length
   target_val = target_array(iTarget)%arr
   print *, target_val
   ! alternatively, you can use the variable directly:
   mySum = sum( target_array(iTarget)%arr )
   print *, mySum
end do

end program

Upvotes: 1

jcerar
jcerar

Reputation: 477

Your python code implicitly generates "array of arrays", where as in Fortran dimensions must be explicitly defined. So the following line does not make much sense:

target_array = [a,b]

target_array is scalar, where as a and b are vectors, so equivalence cannot apply. Additionally target_array has parameter attribute for some reason?

To achieve same as your python example try something like:

program main
  implicit none
  real, dimension(2,2,2)    :: a
  real, dimension(2,2,2)    :: b
  real, dimension(2,2,2,2)  :: target_array
  real                      :: target_var
  integer                   :: i, j, k, l

  target_array(:,:,:,1) = a
  target_array(:,:,:,2) = b

  do i = 1, size(target_array,DIM=4)
    do j = 1, size(target_array,DIM=3)
      do k = 1, size(target_array,DIM=2)
        do l = 1, size(target_array,DIM=2)
          target_var = target_array(l,k,j,i)
          ! ... 
        end do
      end do
    end do
  end do

end program main

Or alternatively in Fortran you can perform operations on a whole array e.g:

target_array(:,:,:,:) = target_array(:,:,:,:) * 2.0

Upvotes: 1

Related Questions