2011-09-21 41 views
2

我已经编写了一个程序来读取包含多维数据的文件(最常见的是3D,但也可能出现2D)。为了提高简单性,我想将数据存储在相同级别的数组中(或假装为一个数组),即使用3D数据的三维阵列等;麻烦的是该程序仅在读取数据文件时了解维度。在运行时设置数组的排名

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

我该如何使用指针排序重映射或其他一些更合适的技术来在运行时设置数组的排名 - 以防万一这样做。或者我最好坚持我目前使用的排名第一的阵列?

+4

怎么样声明数组为3D和2D让最后一个维度的范围只有1:1? –

回答

4

我曾问过类似的东西,即如何看待二维数组作为一个维度,在这里看到:changing array dimensions in fortran

的答案是关于指针的RESHAPE禀,但似乎没有办法,除非你使用子程序包装使用相同的阵列,但你需要回调有最终的子程序只有一个名字,所以问题变得更大。

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情况作为一个特殊的3D情况下与第三维1.

EDIT2:还,请注意将非连续数组传递给具有显式形状数组的子例程:http://software.intel.com/sites/products/documentation/hpc/compilerpro/en-us/fortran/lin/compiler_f/optaps/fortran/optaps_prg_arrs_f.htm

+0

感谢您的回复。你说得对,我想用同一个名字,不管排名如何,在你的文章中(不是在你的评论中),你声称这是可能的。您所发布的代码是否是您在文本中提及的方法? – canavanin

+1

是的,我的意思是这个名字总是'data',然后你将命名问题移动到具有不同名称的子例程。后者可以通过使用回调来解决,即有一个函数'my_sub'可以指向任何一个子例程,但是这样做非常繁琐(我从来没有这样做过,只是仔细阅读它才有可能)。在一个侧面说明中,当我遇到这个(经常)我只是使用手动索引的秩1阵列,或设置多余的维度为1(我相应地编辑我的答案,这里的空间不多了) – steabert

+0

Thanks!你的建议似乎对我很有用:) – canavanin

4

如果我理解正确,你读入数据和一维数组,并希望将它分配给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 
+0

我认为OP要的是同一个名字,但这是不可能的。所以我想这是更好的解决方案之一。 – steabert

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 
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数组。你可以调用填充接口而不是调用单独的子程序。它会自动选择相关的一个。