It’s often required to reshape arrays used in Fortran code. This can be achieved
in several ways, the most naive of which is to use hand-coded do
loops. This
is not recommended as it is error-prone and verbose. A better approach is to use
the intrinsic reshape
function, which is concise and clear.
The most efficient way to reshape arrays is to use pointers. This is a more
advanced approach and care must be taken to ensure that (a) the original array
is not deallocated while the pointer is still in use and (b) you are aware that
modifications to the “reshaped” array will modify the original array and vice
versa because they share the same memory.
It’s often required to reshape arrays used in Fortran code. This can be achieved
in several ways, the most naive of which is to use hand-coded do
loops. This
is not recommended as it is error-prone and verbose. A better approach is to use
the intrinsic reshape
function, which is concise and clear.
The most efficient way to reshape arrays is to use pointers. This is a more
advanced approach and care must be taken to ensure that (a) the original array
is not deallocated while the pointer is still in use and (b) you are aware that
modifications to the “reshaped” array will modify the original array and vice
versa because they share the same memory.
The pack
and unpack
intrinsics can also be used to reshape arrays but this
is not their intended purpose and they are less efficient than reshape
at
achieving this.
It is also possible to do implicit reshaping of arrays by passing them to
procedures with different interface shapes. This is generally not recommended as
it can lead to confusing code and requires compiler flags such as
-fallow-argument-mismatch
in the case of gfortran
.
Example Code
The 1D to 2D reshape coded by hand in
integer, parameter :: m = 3, n = 4
integer, parameter :: mn = m * n
real , dimension(mn) :: arr1d
real , dimension(m, n) :: arr2d
! Initialisation of arr1d omitted
! Hand-coded reshape
do j = 1, n
do i = 1, m
arr2d(i, j) = arr1d((i - 1) * n + j)
end do
end do
can be implemented using reshape
as simply
arr2d = reshape(arr1d, shape(arr2d))
To implement this using pointers, use the c_f_pointer
subroutine and c_loc
function from the iso_c_binding
module (intrinsic since Fortran 2003). The
c_f_pointer
subroutine associates a C pointer with a Fortran pointer, which
allows you to “reshape” the array simply by aliasing (without copying data).
use iso_c_binding, only: c_f_pointer, c_loc
integer, parameter :: m = 3, n = 4
integer, parameter :: mn = m * n
real, target, dimension(mn) :: arr1d
real, pointer :: arr2d(:,:)
! Initialisation of arr1d omitted
! Associate arr2d with arr1d, reshaping it to (m, n)
call c_f_pointer(c_loc(arr1d), arr2d, [m, n])
! Use arr2d as needed
! Don't forget to nullify the pointer when it's no longer needed
nullify(arr2d)