2

グリッド内のすべてのポイントをループし、各ポイントについて、特定の条件が十分な数の隣接ポイントに対して保持されているかどうかを確認するコードがあります。さらに、グリッド上に周期的な境界があります。

この問題はライフゲームとよく似ています。

私の現在のコードは次のようになります

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

これはエレガントでもなく、おそらく非常に効率的でもありません。これを行うより良い方法はありますか?このコードは何度も繰り返されるので、できるだけ速くしたいと思います。

4

3 に答える 3

5

これを2Dで処理し、3Dに膨らませるのはあなたに任せます。

私が最初にすることは、関心のある近傍の深さに等しい深さのハローで配列をパディングすることです。したがって、配列が次のように宣言されている場合、

real, dimension(100,100) :: my_array

そして、あなたは各セルの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

これにより、境界のチェックにかかる時間を大幅に節約でき、次の提案に従うかどうかを確認する価値があります。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

ここでは、の近傍が基準を満たしているlogical_function_of()場合にtrueを返します。my_array(i,j)N、S、E、Wネイバーをリストした後、私は疲れました。プロダクションコードの場合は、とにかくインデックスの関数としてこれを記述します。私の経験forallでは、(一部の人にとっては)エレガントですが、ネストされたループほど高性能ではありません。

于 2012-06-19T10:51:22.800 に答える
1

gridグリッド上のすべてのポイントに対して27回関数を呼び出しています。高価な電話の場合は、電話の回数を減らしたいと思います。

たとえばgrid、真の値を返す可能性が低い場合は、グリッド上のすべてのポイントに対してそれを呼び出し、条件が成立するポイントをkdツリーに格納できます。次に、すべてのポイントの隣接点を数えて、kdツリー内のポイントを反復処理する方が簡単です。

それ以外の場合は、次元のビットマトリックスを使用して、。を使用しisize*jsize*3てすべてのポイントのグリッドの値をキャッシュできますkk=k-1,k+1。それが大きすぎる場合は、isize*3*3キャッシュにサイズのビット行列を使用して中間ソリューションを選択できます。

于 2012-06-19T11:16:04.573 に答える
1

kd-tree または octree を使用して、3d 配列を細分化できます。az morton 次数曲線のような空間充填曲線は、3D で 8 つの立方体のキーを作成するのに役立ちます。しかし、これは 2 の累乗の 3 次元配列で最もうまく機能します。

于 2012-06-19T10:04:46.237 に答える