基于Fortran 90中“find”的逻辑索引

时间:2017-09-05 17:32:34

标签: indexing fortran intel-fortran large-data

我正在尝试使用一些不同的方法()循环2)ANY,使逻辑数组(B)用于基于数组(EP_G2)中.1和.999之间的值的逻辑索引。

program flux_3d

implicit none 
INTEGER :: RMAX, YMAX, ZMAZ, timesteps
DOUBLE PRECISION, PARAMETER ::  pmin=0.1
DOUBLE PRECISION, PARAMETER ::  pmax=0.999
INTEGER :: sz
DOUBLE PRECISION, ALLOCATABLE :: EP_G2(:,:), C(:)
INTEGER, DIMENSION(RMAX*ZMAX*YMAX) :: B
LOGICAL, DIMENSION(RMAX*ZMAX*YMAX) :: A
! dimensions of array, 
RMAX = 540 
YMAX = 204 
ZMAX = 54 
timesteps = 1
!Open ascii array
OPEN(100, FILE ='EP_G2', form = 'formatted')
ALLOCATE( EP_G2(RMAX*ZMAX*YMAX, timesteps))
READ(100, *) EP_G2

WHERE(pmin<EP_G2(:,timesteps)<pmax) B = 1 
    ELSEWHERE
        B = 0
ENDWHERE

PRINT*, B

! SZ # OF POINTS IN B
sz = count(B.eq.1)

!alternate way of finding points between pmin and pmax
A = ANY(pmin<EP_G2(:,t)<pmax)
print*, sz

!Then use the logical matrix B (or A) to make new array 
!Basically I want a new array that isolates just the points in array between 
!pmin and pmax
ALLOCATE(C(sz))
C = EP_G2(LOGICAL(B), 1)

我得到的问题是我要么得到整个数组,要么没有任何东西,而命令LOGICAL(B)得到的错误是它不正确。我是来自Matlab的Fortran的新手,我将使用find。 此外,由于此阵列超过5,948,640 x 1计算时间是一个问题。我正在使用英特尔Fortran编译器(我相信15.0)。

基本上,我正在寻找在两个数字之间找到数组中点的索引的最快方法。

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:2)

我对你的代码和问题感到有些困惑,但我认为你想要找到数组中元素的索引,其值在0.10.999之间。你并不完全清楚你想要的是指数,或者仅仅是元素本身,但是请耐心等待,我会解释如何获得两者。

假设您的原始数组声明为

real, dimension(10**6) :: values

并且它填充了值。然后我可以像这样声明一个索引数组

integer, dimension(10**6) :: indices = [(ix,ix=1,10**6)]  

(显然你也需要声明变量ix。)

现在,表达式

pack(indices, values>pmin.and.values<pmax)

将返回indices的元素,其值严格位于pminpmax之间。当然,如果您只想要值本身,您可以完全省略indices并写入

pack(values, values>pmin.and.values<pmax)

pack的这两种用法都将返回排名为1的数组,并且您可以将返回的数组分配给可分配的,Fortran将为您处理大小调整。

我会留给你将这种方法扩展到你实际使用的rank-2数组,但这样做应该不会太难。如果需要,请寻求更多帮助。

这是最快的方法吗?我不确定,但编写起来非常快,如果你对它的运行时性能感兴趣,我建议你测试一下。

顺便提一下,Fortran内部函数logical用于将logical值从一种转换为另一种,它不是在整数(或任何其他内在类型)上定义的。 Fortran早于将01视为逻辑值的疯狂。

答案 1 :(得分:1)

阵列如何相同?

RMAX,YMAX,ZMAZ和时间步长值在声明A,B和C之后才知道 - 因此它们(A和B)可能不是您想要的大小。

implicit none 
INTEGER :: RMAX, YMAX, ZMAZ, timesteps
DOUBLE PRECISION, PARAMETER ::  pmin=0.1
DOUBLE PRECISION, PARAMETER ::  pmax=0.999
INTEGER :: sz
DOUBLE PRECISION, ALLOCATABLE :: EP_G2(:,:), C(:)
INTEGER, DIMENSION(RMAX*ZMAX*YMAX) :: B 
LOGICAL, DIMENSION(RMAX*ZMAX*YMAX) :: A
! dimensions of array, 
RMAX = 540 
YMAX = 204 
ZMAX = 54 
timesteps = 1

你可能想要这个:

implicit none 
INTEGER ,         PARAMETER :: RMAX      = 504
INTEGER ,         PARAMETER :: YMAX      = 204
INTEGER ,         PARAMETER :: ZMAZ      = 54
INTEGER ,         PARAMETER :: timesteps = 1
DOUBLE PRECISION, PARAMETER :: pmin      = 0.1
DOUBLE PRECISION, PARAMETER :: pmax      = 0.999
INTEGER :: sz
DOUBLE PRECISION, ALLOCATABLE :: EP_G2(:,:), C(:)
INTEGER, DIMENSION(RMAX*ZMAX*YMAX) :: B 
LOGICAL, DIMENSION(RMAX*ZMAX*YMAX) :: A
! dimensions of array, 
!RMAX = 540 
!YMAX = 204 
!ZMAX = 54 
!timesteps = 1

或者这个:

implicit none 
! dimensions of array
INTEGER ,         PARAMETER :: RMAX      = 504
INTEGER ,         PARAMETER :: YMAX      = 204
INTEGER ,         PARAMETER :: ZMAZ      = 54
INTEGER ,         PARAMETER :: timesteps = 1

DOUBLE PRECISION, PARAMETER :: pmin      = 0.1
DOUBLE PRECISION, PARAMETER :: pmax      = 0.999
INTEGER :: sz
DOUBLE PRECISION, ALLOCATABLE :: EP_G2(:,:), C(:)
INTEGER, DIMENSION(:), ALLOCATABLE  :: B 
LOGICAL, DIMENSION(:), ALLOCATABLE  :: A
! Then allocate A and B

您可能还想考虑使用SHAPE或SIZE来查看数组的等级和大小是否正确。

IF(SHAPE(A) /= SHAPE(B) )  ... chuck and error message.
IF(SIZE(A,1) /= SIZE(B,1) ) etc