Suppose I have some subroutine in Fortran, and the arguments are multidimensional arrays. Suppose the rank can be various. Is that possible to have a general setting, than a predefined some array(:,:,:)
?
For example, the following code, how to generalize it that I can use rank_A
to declare the rank of A
, preferably not if rank_A==1 real dimension(:) ... elif rank_A ==2 real dimension(:,:) elif rank_A == 3, real dimension(:,:,:)...
and possibly reshape to adjust it. The reshape can depend the rank of the input array, so introduces variations to the array after reshape as well.
program test_array
implicit none
real, dimension(:,:,:), allocatable :: my_array
integer :: rank_A
rank_A = 3
allocate(my_array(3, 3, 3))
my_array = 1.0
call print_element(my_array, rank_A)
deallocate(my_array)
contains
subroutine print_element(A, rank_A)
real, dimension(:,:,:), intent(in) :: A
real, dimension(:,:,:), allocatable :: my_array_2
integer, intent(in) :: rank_A
integer :: n1, n2, n3
n1 = size(A, 1)
n2 = size(A, 2)
n3 = size(A, 3)
if (rank_A == 3) then
write(*, *) A(1, 1, 1)
allocate(my_array_2(n3, n2, n1))
my_array_2 = reshape(A, shape=[n3, n2, n1], order=[3, 2, 1])
write(*, *) my_array_2(1, 1, 1)
deallocate(my_array_2)
end if
end subroutine
end program
Updated. I tried to use assume size (*)
to pass multidimensional array into 1 dimensional and reconstruct it by indices. However, reshape
does not work. May I know why reshape
does not work here and could it work by some fixing?
Updated 2. Adding B = reshape(A(:size(B)), (/ 3, 3, 3 /))
would work, but this approach still assumes we know the rank of B
after given transpose. Seems the only solution is like Fortran: Choosing the rank of an allocatable array
define higher rank entry, and allocate to 1 dimension if needed
25 | B = reshape(A, (/ 3, 3, 3 /)) ! Corrected syntax
| 1
Error: The upper bound in the last dimension must appear in the reference to the assumed size array ‘a’ at (1)
module array_utils
implicit none
private
public :: print_element
contains
subroutine print_element(A, dims)
real, intent(in) :: A(*)
integer, intent(in) :: dims(:)
real :: B(3,3,3)
integer :: i, j, k, n1, n2, n3
if (size(dims) == 3) then
n1 = dims(1)
n2 = dims(2)
n3 = dims(3)
i = 1
j = 1
k = 1
write(*, *) "A(1, 1, 1) = ", A((k - 1) * n1 * n2 + (j - 1) * n1 + i)
!comment out the reshape line will work
B = reshape(A, (/ 3, 3, 3 /))
end if
end subroutine
end module array_utils
program test_array
use array_utils
implicit none
real, dimension(:,:,:), allocatable :: my_array
integer, dimension(3) :: dims
allocate(my_array(3, 3, 3))
my_array = 1.0
dims = shape(my_array)
call print_element(my_array, dims)
end program