Reputation: 59
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
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
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
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