存储要沿所有维度操作的多维数组
store multi dimensional arrays to be operated on along all the dimensions
前言
我正在编写的 Fortran 程序应该根据 ndims
处理 1D、2D 和 3D 问题,它可以是 1、2 或 3,并且是从输入文件中读取的。
在这些情况下,感兴趣的 quantity/ies 可以存储在数组中(一个可以命名为 phi
)
- 排名
dims
(ALLOCATABLE(:)
或 ALLOCATABLE(:,:)
或 ALLOCATABLE(:,:,:)
),
- 或在秩为 3 的数组中(
ALLOCATABLE(:,:,:)
二维中第三维设置为 1 或一维中第二维和第三维均设置为 1);
这两种情况在 this answer 中都有很好的解释。第一种方法对我来说似乎更优雅,但在下文中我假设第二种方法,这绝对更简单。
这些量必须由几个子程序(例如mysub
)沿着ndims
维度(沿着"pencils"应该给出一个图形的想法)进行操作,所以我应该调用一些东西喜欢
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
(这里mysub2
作用于mysub
的位置。)
所以问题是我应该如何存储 phi,以便我可以用第二个代码替换第一个代码?
也许我可以 return 前言并决定遵循第 1 点,在这种情况下编写通用接口会更容易。我认为,这只是 "hide" 正是 SELECT CASE
会做的事情的一种方式。这两个 (SELECT CASE
/generic INTERFACE
) 中哪个更有效?
这是解决这个问题的唯一两种方法吗?
您可能想要这样的东西:
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
也许我理解错了,但我认为具体问题的答案是根本不对phi的存储或声明进行任何更改。
在原始代码中,三维数据(将数据的秩与用于存储数据的数组的秩区分开来)沿第一维切片处理,然后是第二维,然后是第三维。二维数据按第一个处理,然后是第二个,一维数据只按第一个处理。
所以随着 id 从 1 到数据中的维数,考虑以下 mysub2
的实现:
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
~~
通用接口总是可以在 "compile time" 处解析 - 将由特定 CALL 语句或函数引用调用的特定过程(非类型绑定)或绑定(类型绑定)可以通过查看来确定在代码中的声明处。
如果您遇到 "runtime" 信息会影响过程选择的情况,那么必须有一些其他的可执行机制,除了泛型解析之外或附加到泛型解析中播放 - if 语句、select 案例、动态调度等
因此,询问通用解决方案是否比可执行决策更有效并没有特别的意义——它们是不同的东西。
前言
我正在编写的 Fortran 程序应该根据 ndims
处理 1D、2D 和 3D 问题,它可以是 1、2 或 3,并且是从输入文件中读取的。
在这些情况下,感兴趣的 quantity/ies 可以存储在数组中(一个可以命名为 phi
)
- 排名
dims
(ALLOCATABLE(:)
或ALLOCATABLE(:,:)
或ALLOCATABLE(:,:,:)
), - 或在秩为 3 的数组中(
ALLOCATABLE(:,:,:)
二维中第三维设置为 1 或一维中第二维和第三维均设置为 1);
这两种情况在 this answer 中都有很好的解释。第一种方法对我来说似乎更优雅,但在下文中我假设第二种方法,这绝对更简单。
这些量必须由几个子程序(例如mysub
)沿着ndims
维度(沿着"pencils"应该给出一个图形的想法)进行操作,所以我应该调用一些东西喜欢
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
(这里mysub2
作用于mysub
的位置。)
所以问题是我应该如何存储 phi,以便我可以用第二个代码替换第一个代码?
也许我可以 return 前言并决定遵循第 1 点,在这种情况下编写通用接口会更容易。我认为,这只是 "hide" 正是 SELECT CASE
会做的事情的一种方式。这两个 (SELECT CASE
/generic INTERFACE
) 中哪个更有效?
这是解决这个问题的唯一两种方法吗?
您可能想要这样的东西:
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
也许我理解错了,但我认为具体问题的答案是根本不对phi的存储或声明进行任何更改。
在原始代码中,三维数据(将数据的秩与用于存储数据的数组的秩区分开来)沿第一维切片处理,然后是第二维,然后是第三维。二维数据按第一个处理,然后是第二个,一维数据只按第一个处理。
所以随着 id 从 1 到数据中的维数,考虑以下 mysub2
的实现:
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
~~
通用接口总是可以在 "compile time" 处解析 - 将由特定 CALL 语句或函数引用调用的特定过程(非类型绑定)或绑定(类型绑定)可以通过查看来确定在代码中的声明处。
如果您遇到 "runtime" 信息会影响过程选择的情况,那么必须有一些其他的可执行机制,除了泛型解析之外或附加到泛型解析中播放 - if 语句、select 案例、动态调度等
因此,询问通用解决方案是否比可执行决策更有效并没有特别的意义——它们是不同的东西。