2016-04-12 8 views
0

私はいくつかのデータ型を一緒に扱う作業をしています。文字、いくつかの整数、および倍精度値が含まれます。これらは、問題の解決方法を表します。派生データ型のF90でMPI_GATHER/MPI_GATHERVに問題がある

現時点では、私は "おもしろい" F90プログラムを持っています。これは、プロセッサごとに乱数と人為的な文字列を持つMPIを使用しています。文字と倍精度の乱数を一緒に持つデータ型が必要です。

MPI_REDUCEを使用して、倍精度値の最小値を取得します。 MPI_GATHERV関数を介してルート(ランク= 0)にまとめられた各プロセスのデータ型を取得します。

私の目標は、乱数値の最小値とデータ型を一致させることです。それは最終的な答えになります。私はこの時点まで、あらゆる種類のアイデアを試してみましたが、無駄です。私は "forrtl:severe SIGSEGV、セグメンテーションフォールトが発生しました"と終わります。

他の投稿もいくつか見てきました。たとえば、私はこの特定のシステムで "mpif.hを使用"ステートメントを使用することはできません。

しかし、最後に、ここでのコードは次のとおりです。

program fredtype 
    implicit none 
    include '/opt/apps/intel15/mvapich2/2.1/include/mpif.h' 



    integer rank,size,ierror,tag,status(MPI_STATUS_SIZE),i,np,irank 
    integer blocklen(2),type(2),num,rcount(4) 
    double precision :: x,aout 
    character(len=4) :: y 

    type, BIND(C) :: mytype 
    double precision :: x,aout,test 
    character :: y 
    end type mytype 

    type(mytype) :: foo,foobag(4) 
    integer(KIND=MPI_ADDRESS_KIND) :: disp(2),base 


    call MPI_INIT(ierror) 

call MPI_COMM_SIZE(MPI_COMM_WORLD,size,ierror) 
    call MPI_COMM_RANK(MPI_COMM_WORLD,rank,ierror) 

    aout = 99999999999.99 

    call random_seed() 
    call random_number(x) 



    if(rank.eq.0)y="dogs" 
    if(rank.eq.1)y="cats" 
    if(rank.eq.2)y="tree" 
    if(rank.eq.3)y="woof" 

    print *,rank,x,y 


    call MPI_GET_ADDRESS(foo%x,disp(1),ierror) 
    call MPI_GET_ADDRESS(foo%y,disp(2),ierror) 

    base = disp(1) 
call MPI_COMM_SIZE(MPI_COMM_WORLD,size,ierror) 
    call MPI_COMM_RANK(MPI_COMM_WORLD,rank,ierror) 

    aout = 99999999999.99 

    call random_seed() 
    call random_number(x) 



    if(rank.eq.0)y="dogs" 
    if(rank.eq.1)y="cats" 
    if(rank.eq.2)y="tree" 
    if(rank.eq.3)y="woof" 

    print *,rank,x,y 


    call MPI_GET_ADDRESS(foo%x,disp(1),ierror) 
    call MPI_GET_ADDRESS(foo%y,disp(2),ierror) 

    base = disp(1) 
call MPI_COMM_SIZE(MPI_COMM_WORLD,size,ierror) 
    call MPI_COMM_RANK(MPI_COMM_WORLD,rank,ierror) 

    aout = 99999999999.99 

    call random_seed() 
    call random_number(x) 



    if(rank.eq.0)y="dogs" 
    if(rank.eq.1)y="cats" 
    if(rank.eq.2)y="tree" 
    if(rank.eq.3)y="woof" 

    print *,rank,x,y 


    call MPI_GET_ADDRESS(foo%x,disp(1),ierror) 
    call MPI_GET_ADDRESS(foo%y,disp(2),ierror) 

    base = disp(1) 
    disp(2) = disp(2) - base 

    blocklen(1) = 1 
    blocklen(2) = 1 

    type(1) = MPI_DOUBLE_PRECISION 
    type(2) = MPI_CHARACTER 


    call MPI_TYPE_CREATE_STRUCT(2,blocklen,disp,type,foo,ierror) 
    call MPI_TYPE_COMMIT(foo,ierror) 




     call MPI_REDUCE(x,aout,1,MPI_DOUBLE_PRECISION,MPI_MIN,0,MPI_COMM_WORLD,i\ 
error) 

     call MPI_GATHER(num,1,MPI_INT,rcount,1,MPI_INT,0,MPI_COMM_WORLD) 
     call MPI_GATHERV(foo,num,type,foobag,rcount,disp,type,0,MPI_COMM_WORLD) 


     if(rank.eq.0)then 
      print *,'fin ',aout 

      end if 




end program fredtype 

は、任意の助けてくれてありがとう。 よろしくお願い致します。 Erin

+0

ちょうどサニティチェックでは、あなたの実際のコードはあなたがここに投稿したバージョンのミドルブロックを3回繰り返さないのですか?私はそれが問題を引き起こすとは思わないが、それは間違いなく間違っている。 – Gilles

答えて

1

あなたのコードは完全に修正しようとするのは間違いです。それでは、あなたは次のように定義されたあなたのタイプmytypeを持っていると仮定しましょう:

type, bind(C) :: mytype 
    double precision :: x, aout, test 
    character(len=4) :: y 
end type mytype 

(Rkの:それはあなたの元のコードから欠落しているように見えたとして、私はyの定義にlen=4を追加しました私はそれ間違っているかもしれません。そのそうであれば、ちょうどそれに応じて、後続のコードでblocklen(2)を調整)

さて、あなただけのタイプmytypeのあなたの変数のxyフィールドを転送したいと仮定しましょう。このためには、最初にMPI_Type_create_struct()を使用して基本タイプとその位置を構造体に定義し、次にMPI_Type_create_resized()を使用して、穴を含むタイプの真の範囲と下限を定義する適切な派生MPIタイプを作成する必要があります。

通常、難しい部分は、Fortranタイプの下限と範囲を評価することです。ここでは、最初と最後を転送するフィールドに含めて、bind(C)を追加したときに、MPI_Type_get_extend()を使用してこれらの情報を取得できます。ただし、またはy(タイプの最初と最後のフィールド)をMPIデータタイプに含めなかった場合、MPI_Type_get_extent()は必要なものを返さないでしょう。だから私はあなたに、私は信じています代替(やや面倒な)アプローチを提案します、常に動作:

integer :: ierror, typefoo, tmptypefoo 
integer :: blocklen(2), types(2) 
type(mytype) :: foobag(4) 
integer(kind=MPI_ADDRESS_KIND) :: disp(2), lb, extent 

call MPI_Get_address(foobag(1), lb, ierror) 
call MPI_Get_address(foobag(1)%x, disp(1), ierror) 
call MPI_Get_address(foobag(1)%y, disp(2), ierror) 
call MPI_Get_address(foobag(2), extent, ierror) 
disp(1) = MPI_Aint_diff(disp(1), lb) 
disp(2) = MPI_Aint_diff(disp(2), lb) 
extent = MPI_Aint_diff(extent, lb) 
lb = 0 

blocklen(1) = 1 
blocklen(2) = 4 

types(1) = MPI_DOUBLE_PRECISION 
types(2) = MPI_CHARACTER 

call MPI_Type_create_struct(2, blocklen, disp, types, tmptypefoo, ierror) 
call MPI_Type_create_resized(tmptypefoo, lb, extent, typefoo, ierror) 
call MPI_Type_commit(typefoo, ierror) 

だから、あなたが見ることができるように、lbは構造への変位のためのベースアドレスとして機能し、型エクステントは、タイプmytypeの配列の2つの連続した要素の相対アドレスを使用して計算されます。
次に、転送する実際のデータに関する情報のみを含む中間MPIデータタイプtmptypefooを作成し、Fortranタイプの実際の下限と範囲に関する情報をtypefooに拡張します。最後に、この最後のものだけがデータ転送に役立つため、コミットする必要があります。

+0

うわー!これは最高です!どうもありがとうございました。私はもう1つ質問してください:私はtypefooをMPI_GATHERV関数に渡しますか?再度、感謝します。 – user1544953

関連する問題