2011-06-28 30 views
1

この質問は、MPI_type_create_subarrayとMPI_Gatherの既存のスレッドに続きます。私の目的は、MPI_Type_Create_SubarrayとFortran 90のMPI_Gathervを使って、マスタープロセス(ランク= 0)上のすべてのスレーブプロセス(4つの番号)からより大きい配列のサブアレイを大規模な配列に集めることです。プロジェクト。以下は、私のサンプルコードです:しかしFortran用MPI_Gathervを使用

program main 
    implicit none 
    include "mpif.h" 
    integer :: ierr, myRank, nProcs 
    integer :: sendsubarray, recvsubarray, resizedrecvsubarray 
    integer, dimension(2) :: starts,sizes,subsizes 
    integer, dimension(:), allocatable :: counts, disps 
    integer, parameter :: nx_glb=10, ny_glb=10, nx=5, ny=5 
    integer, dimension(:,:), target, allocatable :: mat, matG 
    integer, pointer :: sendPtr(:,:), recvPtr(:,:) 
    integer :: i, j 

    call mpi_init(ierr) 
    call mpi_comm_rank(mpi_comm_world, myRank, ierr) 
    call mpi_comm_size(mpi_comm_world, nProcs, ierr) 

    sizes(1)=nx+2; sizes(2)=ny+2 
    subsizes(1)=nx; subsizes(2)=ny 
    starts(1)=2; starts(2)=2 
    call mpi_type_create_subarray(2, sizes, subsizes, starts, mpi_order_fortran, & 
           mpi_integer, sendsubarray, ierr) 
    call mpi_type_commit(sendsubarray,ierr) 

    allocate(mat(1:nx+2,1:ny+2)) 
    do j=1, ny+2 
    do i=1, nx+2 
     if(i.eq.1 .or. i.eq.nx+2 .or. j.eq.1 .or. j.eq.ny+2) then 
     mat(i,j)=1000 
     else 
     mat(i,j) = myRank 
     end if 
    end do 
    end do 

    sendPtr=>mat 
    if(myRank.eq.0) then 
    allocate(matG(nx_glb,ny_glb)) 
    matG=1000 
    sizes(1)=nx_glb; sizes(2)=ny_glb 
    subsizes(1)=nx; subsizes(2)=ny 
    starts(1)=1; starts(2)=1 
    call mpi_type_create_subarray(2, sizes, subsizes, starts, mpi_order_fortran, & 
            mpi_integer, recvsubarray, ierr) 
    call mpi_type_commit(recvsubarray, ierr) 
    call mpi_type_create_resized(recvsubarray, 1, sizeof(i), resizedrecvsubarray, ierr) 
    call mpi_type_commit(resizedrecvsubarray,ierr) 
    recvPtr=>matG 
    end if 

    counts(1:4) = (/1, 1, 1, 1/) 
    disps(1:4) = (/0, 5, 50, 55/) 
    call mpi_gatherv(sendPtr,1,sendsubarray,recvPtr,counts,disps,resizedrecvsubarray, & 
        0,mpi_comm_world,ierr) 

    if(myRank.eq.0) then 
    do i=1, nx_glb 
     write(1000,*) (matG(i,j),j=1, ny_glb) 
    end do 
    end if 

    call mpi_finalize(ierr) 

    end program main 

forrtl: severe(174): SIGSEGV, segmentation fault occurredにこのコードの結果を実行します。

私は、初期化や収集中に宣言されていない配列の変数/位置を指し示そうとしているようです。私は多くの方法でデバッグしようとしましたが、無駄でした。

事前に感謝します。

答えて

1

ここで主な問題が発生したら、あなたは自分を蹴るでしょう。カウントやディスペンスを割り当てていませんでした。

include mpif.hではなく、use mpiを使用することを強くお勧めします。 use文(暗黙的なnoneの前)は、より良い型チェックを持つF90インタフェースをもたらします。これを行うと、あなたのタイプがサイズ変更された場合、kindmpi_address_kindの整数が必要になることもわかります。

更新

[OK]を、gathervを行う方法の大きな問題のためので、あなたは主に右のものを持っていましたが、あなたは正しい、開始、dispsなどはゼロインデックスを作成する必要があり、実際のMPIライブラリは、FORTRANバインディングを使用していても、Cの観点から操作を行っているため、1ではありません。したがって、sendsubarrayでは、開始は[1,1]でなければなりません。 recvサブ配列の場合は[0,0]でなければならず、resize、startは0でなければならず、extentはsizeof(type)でなければなりません(両方ともkind mpi_address_kindの整数でなければなりません)。

私はこれらの更新を使用してコードのバージョンを付加していて、基礎となる配列が文字型であることと、それは診断をプリントアウトし、何が起こっているかを確認するために簡単ですので:

program main 
    use mpi 
    implicit none 
    integer :: ierr, myRank, nProcs 
    integer :: sendsubarray, recvsubarray, resizedrecvsubarray 
    integer, dimension(2) :: starts,sizes,subsizes 
    integer, dimension(:), allocatable :: counts, disps 
    integer, parameter :: nx_glb=10, ny_glb=10, nx=5, ny=5 
    character, dimension(:,:), target, allocatable :: mat, matG 
    character :: c 
    integer :: i, j, p 
    integer(kind=mpi_address_kind) :: start, extent 

    call mpi_init(ierr) 
    call mpi_comm_rank(mpi_comm_world, myRank, ierr) 
    call mpi_comm_size(mpi_comm_world, nProcs, ierr) 

    sizes(1)=nx+2; sizes(2)=ny+2 
    subsizes(1)=nx; subsizes(2)=ny 
    starts(1)=1; starts(2)=1 
    call mpi_type_create_subarray(2, sizes, subsizes, starts, mpi_order_fortran, & 
           mpi_character, sendsubarray, ierr) 
    call mpi_type_commit(sendsubarray,ierr) 

    allocate(mat(1:nx+2,1:ny+2)) 
    mat='.' 
    forall (i=2:nx+1,j=2:ny+1) mat(i,j)=ACHAR(ICHAR('0')+myRank) 

    if(myRank.eq.0) then 
    allocate(matG(nx_glb,ny_glb)) 
    matG='.' 
    sizes(1)=nx_glb; sizes(2)=ny_glb 
    subsizes(1)=nx; subsizes(2)=ny 
    starts(1)=0; starts(2)=0 
    call mpi_type_create_subarray(2, sizes, subsizes, starts, mpi_order_fortran, & 
            mpi_character, recvsubarray, ierr) 
    call mpi_type_commit(recvsubarray, ierr) 
    extent = sizeof(c) 
    start = 0 
    call mpi_type_create_resized(recvsubarray, start, extent, resizedrecvsubarray, ierr) 
    call mpi_type_commit(resizedrecvsubarray,ierr) 
    end if 

    allocate(counts(4),disps(4)) 
    counts(1:4) = (/1, 1, 1, 1/) 
    disps(1:4) = (/0, 5, 50, 55/) 
    call mpi_gatherv(mat,1,sendsubarray,matG,counts,disps,resizedrecvsubarray, & 
        0,mpi_comm_world,ierr) 

    do p=0,nProcs 
     if (myRank == p) then 
     print *, 'Local array for rank ', myRank 
     do i=1, nx+2 
      print *, (mat(i,j),j=1,ny+2) 
     end do 
     endif 
     call MPI_Barrier(MPI_COMM_WORLD,ierr) 
    enddo 
    if(myRank.eq.0) then 
    print *, 'Global array: ' 
    do i=1, nx_glb 
     print *, (matG(i,j),j=1, ny_glb) 
    end do 
    end if 

    call mpi_finalize(ierr) 

end program main 

出力の場合:

Local array for rank   0 
....... 
.00000. 
.00000. 
.00000. 
.00000. 
.00000. 
....... 
Local array for rank   1 
....... 
.11111. 
.11111. 
.11111. 
.11111. 
.11111. 
....... 
Local array for rank   2 
....... 
.22222. 
.22222. 
.22222. 
.22222. 
.22222. 
....... 
Local array for rank   3 
....... 
.33333. 
.33333. 
.33333. 
.33333. 
.33333. 
....... 
Global array: 
0000022222 
0000022222 
0000022222 
0000022222 
0000022222 
1111133333 
1111133333 
1111133333 
1111133333 
1111133333 

...意味がありますか?これは、この質問のCバージョンと非常によく似ていますが、ここで回答していますが(MPI_Type_create_subarray and MPI_Gather)、既に多くのことを考え出していました...

ああ、もう1つのこと - 実際には設定する必要はありませんFortran内のsend/recvデータへのポインタを作成します。 Cでは、ポインタをデータの配列に明示的に渡す必要があります。 Fortranでは、単に配列を渡すことができます(そして、それらはすでに "参照によって渡されています"、例えばCのポインタを変数に渡すことと等価です)。だからあなたは配列を渡すことができます。

+0

ありがとうございました。それは私のところでは本当に愚かでした。しかし、あなたが言及した変更を実装すると、私はFortranの** mpi_type_create_subarray **の 'starts'パラメータについて少し混乱します。私が望むように動作していないことが判明したのは、 'sendsbarray'では2、' recvsubarray'では1であり、1と0であると宣言したからです。また、 'resize'の下限値も0であると考えられます。CとFortranの違いは、C言語では0からF90では1から始まるため、理解できませんでした。ありがとう。 – Vijay

+0

Ok;あなたの質問にはまだ答えていないようです。私は最初の壊滅的なエラーをはるかに超えて見ていませんでした。もう少し見てみましょう... –

+0

ありがとうジョン。私は本当にそれを感謝します。 – Vijay

関連する問題