Многомерные массивы#

Многомерные массивы хранятся в памяти по столбцам. Это означает, что крайний левый (внутренний) индекс обращается к элементам последовательно. С практической точки зрения это означает, что срез массива V(:, 1) непрерывен, а расстояние между элементами в срезе V(1, :) равно размерности столбцов. Это важно при передаче срезов массива процедурам, которые работают с непрерывными в памяти данными.

Локальность памяти важно учитывать в зависимости от вашего приложения, обычно при выполнении операций с многомерной памятью последовательный доступ всегда должен осуществляться шаг за шагом.

В следующем примере оценивается величина обратная расстоянию между двумя наборами точек. Обратите внимание, что точки хранятся последовательно в массивах xyz1/xyz2, а внутренний цикл продвигается по крайнему левому индексу массива a.

subroutine coulomb_matrix(xyz1, xyz2, a)
  real(dp), intent(in) :: xyz1(:, :)
  real(dp), intent(in) :: xyz2(:, :)
  real(dp), intent(out) :: a(:, :)
  integer :: i, j
  do i = 1, size(a, 2)
    do j = 1, size(a, 1)
      a(j, i) = 1.0_dp/norm2(xyz1(:, j) - xyz2(:, i))
    end do
  end do
end subroutine coulomb_matrix

Другим примером может быть снижение размерности трёхмерного массива:

do i = 1, size(amat, 3)
  do j = 1, size(amat, 2)
    do k = 1, size(amat, 1)
      cmat(k, j) = cmat(k, j) + amat(k, j, i) * bvec(i)
    end do
  end do
end do

Непрерывные срезы массива можно использовать при переобозначении с привязкой к массиву, чтобы разрешить использование массивов более высокой размерности в качестве массивов более низкой размерности без необходимости изменения формы и потенциального создания временной копии массива.

Например, это можно использовать для снижения размерности трёхмерного массива с помощью матрично-векторной операции:

subroutine matmul312(amat, bvec, cmat)
  real(dp), contiguous, intent(in), target :: amat(:, :, :)
  real(dp), intent(in) :: bvec(:)
  real(dp), contiguous, intent(out), target :: cmat(:, :)
  real(dp), pointer :: aptr(:, :)
  real(dp), pointer :: cptr(:)

  aptr(1:size(amat, 1)*size(amat, 2), 1:size(amat, 3)) => amat
  cptr(1:size(cmat)) => cmat

  cptr = matmul(aptr, bvec)
end subroutine matmul312