2016-06-28 84 views
0

前言存储多维阵列

的Fortran程序,我正在写应处理取决于ndims 1D,2D和3D的问题,它可以是1,2或3并从输入文件中读取。

在这些情况下的量/所关注IES可以(一个可以被命名为phi)存储在数组

    dimsALLOCATABLE(:)ALLOCATABLE(:,:)ALLOCATABLE(:,:,:))的
  1. 或在等级阵列3(ALLOCATABLE(:,:,:),第三维在2D中等于1或者第二和第三维在1D中等于1);

这两种情况在this answer都有很好的解释。第一种方法对我来说似乎更加优雅,但在下面我假设第二种方法,这绝对简单。

这些量必须由几个子程序上进行操作(如mysub)沿ndims尺寸(沿“铅笔”应该给图形的想法),所以我应该叫像

SELECT CASE (ndims) 

! 3D case 
CASE (3) 
    DO j = ... 
    DO k = ... 
     CALL mysub(phi(:,j,k)) 
    END DO 
    END DO 
    DO i = ... 
    DO k = ... 
     CALL mysub(phi(i,:,k)) 
    END DO 
    END DO 
    DO i = ... 
    DO j = ... 
     CALL mysub(phi(i,j,:)) 
    END DO 
    END DO 

! 2D case 
CASE (2) 
    DO j = ... 
    DO k = ... 
     CALL mysub(phi(:,j,1)) 
    END DO 
    END DO 
    DO i = ... 
    DO k = ... 
     CALL mysub(phi(i,:,1)) 
    END DO 
    END DO 

! 1D case 
CASE (1) 
    DO j = ... 
    DO k = ... 
     CALL mysub(phi(:,1,1)) 
    END DO 
    END DO 
END SELECT 

实际问题

任何人都可以建议我(或帮助我设计!)一种不同的存储方式phi(可能涉及派生数据类型?),以便我可以折叠前面的代码如下?

DO id = 1, ndims 
    CALL mysub2(phi,id) 
END DO 

(这里​​作用mysub的地方。)

所以,问题是我应该如何存储披,这样我就可以用第二个替代第一码?

也许我可以回到前言,并决定按照1点,在这种情况下会更容易编写一个通用的接口。我认为,这只是一种“隐藏”SELECT CASE会做什么的方法。哪两个(SELECT CASE /通用INTERFACE)会更有效率?

这些是面对这个问题只有两个办法?

+0

这正在成为一种常见的东西。最近问昨天 - http://stackoverflow.com/questions/38058080/fortran-choosing-the-rank-of-an-allocatable-array。 –

+0

问题有明显的关联,但这个问题的答案不会回答这个:这个问题,如果我理解正确的,是关于如何选择一个数组的等级;我的问题更多地是关于“编写不依赖于其所操作阵列的等级的代码的最佳方式”。 –

回答

1

也许是我误会了,不过我想答案的具体问题是不能对存储或披声明所有的任何变化。

在原始代码中,三维数据切片中沿着第一维度被处理,则第二,然后第三个(从用于存储数据的阵列的等级区分的数据的等级)。二维数据沿着第一个处理,然后第二个和一维数据沿着第一个处理。

ID为1将在数据的维数

所以,请考虑以下实施​​:

SUBROUTINE mysub2(phi, id) 
    TYPE(pink_elephant), INTENT(IN) :: phi(:,:,:) 
    INTEGER, INTENT(IN) :: id 

    INTEGER :: i, j, k 

    SELECT CASE (id) 
    CASE (1) 
    DO j = ... 
     DO k = ... 
     CALL mysub(phi(:,j,k)) 
     END DO 
    END DO 

    CASE (2) 
    DO i = ... 
     DO k = ... 
     CALL mysub(phi(i,:,k)) 
     END DO 
    END DO 

    CASE (3) 
    DO i = ... 
     DO j = ... 
     CALL mysub(phi(i,j,:)) 
     END DO 
    END DO 

    END SELECT 
END SUBROUTINE mysub2 

~~

通用接口,可以随时在“编译时”来解决 - 可以通过查看代码中的声明来确定将由特定CALL语句或函数引用调用的特定过程(不是类型绑定)或绑定(类型绑定)。

如果您遇到了“运行时间”信息将影响过程选择的情况,那么必须有一些其他可执行机制,除了通用解析之外或附加解决方案 - 即使因此声明后,选择的情况下,动态调度,等,等,等

询问通用的分辨率是否为可执行的决定更有效的是没有什么特殊意义 - 它们是不同的东西。

+0

(然后,也许 “** **高效” 是不正确的字。)在你的代码'SELECT CASE(为ndims)'每次'mysub2'是'CALL'ed执行。如果是使用'SELECT CASE(为ndims)'(类似于什么在我挂了答案完成)选择phi'的'军衔,比'INTERFACE'块可用于调用3个不同的'SUBROUTINE's为3不同的队伍。这不会更快**吗? –

+1

通用接口只是将不同的过程放在同一标识符后面的命名便利性。除了辅助功能之外,您可以简单地将通用名称更改为通用在编译时解析的相关特定名称,并获得完全相同的行为。它们的使用不是执行效率的问题,它们的使用是一个问题:“我输入哪些字符以引用特定的过程”。你是否真的问过“某​​个嵌套迭代结构的哪个层次能够做出特定决策是最有效的”? – IanH

+0

也许我有点困惑。你说我可以简单地将通用名称更改为相关的特定名称。这似乎很简单!我认为SELECT CASE会更慢。我错了吗?如果是这样,为什么? (关于引号中的最后一个问题,我没有明白。) –

1

你可能想是这样的:

program test 

    integer :: j,ndims 
    integer :: n ! rank of each dimension, could also be read from input an allocated separately 

    type arr 
     real(8) :: x(n) ! one array for each dimension 
    end type 

    type(arr),allocatable :: phi 

    read(*,*) ndims 
    allocate(phi(ndims)) 

    do j=1,ndims 
     call mysub(phi(j)%x) ! acts on the array in dimension j 
    end do 

contains 

    subroutine mysub(x) 
    ... 
    end subroutine 

end program 
+0

那么,这可能是一个起点。我希望你能进一步提供帮助。你的答案有效地显示了如何对'ndims'维数进行'DO'循环。另一方面,'arr'不会包含'phi'所包含的相同信息。 –

+0

我在实际问题中增加了一些细节。 –

+0

是的,我想我回答得有点快^^。 – PeMa