快速计算3D阵列中的相邻点

paf*_*fcu 2 optimization fortran

我有一个代码,我想循环遍历网格中的所有点,并为每个点检查给定条件是否适用于足够数量的相邻点.另外,我在网格上有周期性边界.

问题与生命游戏非常相似.

我当前的代码看起来像这样

do k=1,ksize; do j=1,jsize; do i=1,isize ! Loop over all points
  ncount = 0
  kkloop: do kk=k-1,k+1 ! Loop over neighbours
    ktmp = kk
    if(kk>ksize) ktmp = 1 ! Handle periodic boundary
    if(kk<1) ktmp = ksize
    do jj=j-1,j+1
      jtmp = jj
      if(jj>jsize) jtmp = 1
      if(jj<1) jtmp = jsize
      do ii=i-1,i+1
        if(ii == 0 .and. jj == 0 .and. kk == 0) cycle ! Skip self
        itmp = ii
        if(ii>isize) itmp = 1
        if(ii<1) itmp = isize

        if(grid(itmp,jtmp,ktmp)) ncount = ncount + 1 ! Check condition for neighbour
        if(ncount > threshold) then ! Enough neigbours with condition?
          do_stuff(i,j,k)
          break kkloop
        end if
      end do
    end do
  end do
end do; end do; end do
Run Code Online (Sandbox Code Playgroud)

这既不优雅,也不高效.有一个更好的方法吗?这段代码会重复很多,所以我想尽可能快地完成.

Hig*_*ark 5

我会在2D中解决这个问题,让它膨胀到3D.

我要做的第一件事是用一个深度等于你感兴趣的邻域深度的光晕填充数组.所以,如果你的数组被声明为,比如说

real, dimension(100,100) :: my_array
Run Code Online (Sandbox Code Playgroud)

你对每个细胞的8个直接邻居感兴趣,

real, dimension(0:101,0:101) :: halo_array
.
.
.
halo_array(1:100,1:100) = my_array
halo_array(0,:) = my_array(100,:)
! repeat for each border, mutatis mutandis
Run Code Online (Sandbox Code Playgroud)

这将节省大量时间检查边界,无论您是否遵循下一个建议,都值得做.如果你愿意的话,你可以"就地"这样做,我的意思是扩展my_array而不是复制它.

对于一个优雅的解决方案,你可以写这样的东西

forall (i=1:100,j=1:100)
   if (logical_function_of(my_array(i-1,j),my_array(i+1,j),my_array(i,j-1),my_array(i,j+1),...) then
      do_stuff(my_array(i,j))
   end if
end forall
Run Code Online (Sandbox Code Playgroud)

在这里,logical_function_of()my_array(i,j)满足您的标准的邻域时返回true .列出N,S,E,W邻居后我感到很累,对于生产代码,我可能会将其作为索引的函数编写.根据我的经验forall,优雅(对某些人来说)但不如嵌套循环那么高.