在运行时设置数组的等级

时间:2011-09-21 13:52:01

标签: multidimensional-array runtime fortran rank

我编写了一个程序,它读取包含多维数据的文件(最常见的是3D,但也可能出现2D)。为了提高简洁性,我想将数据存储在相同等级的数组中(或者假装为一个等级的数据),即使用三维数据进行3D数据等;麻烦的是程序只学习读取数据文件的维度。

目前,我将所有数据存储在排名为1的数组中,并根据元素的坐标计算该数组中每个元素的索引(这也是建议here)。但是,我也读过有关指针等级重新映射的内容,它看起来非常优雅,正是我一直在寻找的内容,因为它可以让我废弃我的数组索引确定程序(这可能远远低于后面的内容)场景)。然而,现在看起来我面临着与直接声明多维数组相同的问题 - 如何进行声明?同样,它需要有关排名的信息。

我如何使用指针等级重新映射或其他更合适的技术在运行时设置数组的等级 - 以防这种情况可以完成。或者我最好坚持我目前正在使用的排名单阵?

4 个答案:

答案 0 :(得分:4)

如果我理解正确,你会读入数据和1-D数组,并希望将其分配给2D或3D数组,只有在读取文件后才知道。为什么不将2D和3D数组声明为可分配数组,并根据数据形状只分配其中一个?您可以使用内在函数RESHAPE来方便地执行此操作。

REAL,DIMENSION(:,:),  ALLOCATABLE :: arr2d
REAL,DIMENSION(:,:,:),ALLOCATABLE :: arr3d
...
! Read data into 1-D array, arr1d;
...
IF(L2d)THEN
  ALLOCATE(arr2d(im,jm))
  arr2d=RESHAPE(arr1d,(/im,jm/))
ELSEIF(L3d)THEN
  ALLOCATE(arr3d(im,jm,km))
  arr3d=RESHAPE(arr1d,(/im,jm,km/))
ENDIF

答案 1 :(得分:4)

我曾经问过类似的东西,即如何将二维数组视为一个维度,请参阅此处:changing array dimensions in fortran

答案是关于指针的RESHAPE instrinsic,但是似乎没有办法使用相同的数组 name ,除非你使用子程序包装器,但是你需要回调来使用最终的子程序只有一个名字,所以问题变大了。

program test
    real, allocatable :: data(:)
    allocate(data(n_data))
    ! read stuff, set is_2d and sizes
    if (is_2d) then
        call my_sub2(data, nX, nY)
    else
        call my_sub3(data, nX, nY, nZ)
    end if
end program test

subroutine my_sub2(data, nX, nY)
    real :: data(nx,nY)
    ! ...
end subroutine my_sub2

subroutine my_sub3(data, nX, nY, nZ)
    real :: data(nx,nY,nZ)
    ! ...
end subroutine my_sub3

编辑:作为替代方案,将第三个等级设为1:

program test
    real, allocatable, target:: data(:)
    real, pointer:: my_array(:,:,:)
    logical is_2d
    n_data = 100
    allocate(data(n_data))
    ! read stuff, determine is_2d and n
    if (is_2d) then
        i=n
        j=n
        k=1
    else
        i=n
        j=n
        k=n
    end if
    my_array(1:i,1:j,1:k) => data
    write(*,*) my_array
end program test

然后将2D案例作为具有第三维1的特殊3D案例处理。

EDIT2:另外,在将非连续数组传递给具有显式形状数组的子例程时要小心:http://software.intel.com/sites/products/documentation/hpc/compilerpro/en-us/fortran/lin/compiler_f/optaps/fortran/optaps_prg_arrs_f.htm

答案 2 :(得分:4)

你可以像这样使用EQUIVALENCE语句:

Program ranks
    integer a_1d(12)
    integer a_2d(2, 6)
    integer a_3d(2, 2, 3)

    equivalence (a_1d, a_2d, a_3d)

    ! fill array 1d
    a_1d = (/1,2,3,4,5,6,7,8,9,10,11,12/)

    print *, a_1d

    print *, a_2d(1,1:6)
    print *, a_2d(2,1:6)

    print *, a_3d(1,1,1:3)
    print *, a_3d(2,1,1:3)
    print *, a_3d(1,2,1:3)
    print *, a_3d(2,2,1:3)

end program ranks

答案 3 :(得分:0)

您可以为不同的数组排列编写子程序并创建一个接口 在示例中,我已经展示了如何使用接口语句`

填充不同数组的数组
program main 
    use data 
    implicit none 
    real,dimension(:,:,:),allocatable::data 
    integer::nx,ny,nz
    nx = 5
    ny = 10
    nz = 7
    call populate(nx,ny,nz,data)
    print *,data
end program main `

数据模块在这里

module data  
  private 
  public::populate
  interface populate 
      module procedure populate_1d 
      module procedure populate_2d 
      module procedure populate_3d 
  end interface
 contains 
   subroutine populate_1d(x,data)
       implicit none 
       integer,intent(in)::x
       real,dimension(:),allocatable,intent(out):: data
       allocate(data(x))
       data=rand()
   end subroutine populate_1d 
   subroutine populate_2d(x,y,data)
       implicit none 
       integer,intent(in)::x,y
       real,dimension(:,:),allocatable,intent(out):: data
       allocate(data(x,y))
       data=rand()
   end subroutine populate_2d 
   subroutine populate_3d(x,y,z,data)
       implicit none 
       integer,intent(in)::x,y,z
       real,dimension(:,:,:),allocatable,intent(out):: data
       allocate(data(x,y,z))
       data=rand()
   end subroutine populate_3d 
end module data 

有一个填充1d,2d和3d数组的接口。你可以调用populate接口而不是调用单个子程序。它会自动选择相关的一个。