2

モジュール、派生データ型、および MPI を使用する Fortran 90 コードでしばらく行き詰まっています。

私が抱えている問題は、派生データ型をブロードキャストした後、マスター ノードの変数のみが正しい値を持ち、他のすべてのノードの変数には必要なものが含まれていないことです。より大きなコードから最小限の例を抽出しました。メインプログラムが含まれています:


include 'hello_types.f90'
include 'mpi_circle.f90'

program hello_world

use type_hello_world
use create_mpi_types

implicit none

include 'mpif.h'

integer         :: ierr, num_procs, my_id, mesg_mpi_circle
type(circle_)       :: circle

call MPI_Init(ierr)

!find out MY process ID, and how many processes were started.

call MPI_COMM_RANK (MPI_COMM_WORLD, my_id, ierr)
call MPI_COMM_SIZE (MPI_COMM_WORLD, num_procs, ierr)

allocate(circle%diameter(3),circle%straal(3))

if (my_id==0) then
print*,'enter straal and diameter'
read*,circle%diameter(1),circle%straal(1)
circle%diameter(2)=circle%diameter(1)
circle%straal(2)=circle%straal(1)
endif

call build_derived_circle(circle,mesg_mpi_circle)

call MPI_BCAST(circle,1,mesg_mpi_circle,0,MPI_COMM_WORLD,ierr)


print *, "Hello world! I'm process ", my_id, " out of", num_procs, " processes."
print*,my_id,mesg_mpi_circle%diameter(my_id+1),mesg_mpi_circle%straal(my_id+1)

call MPI_Finalize(ierr)


end program hello_world

出力には 2 つの print ステートメントが含まれます。最初のステートメントは proc_id のみを出力し (正常に動作します)、2 番目のステートメントはそれぞれのノードの変数を出力します (ここで問題が発生し、マスター ノードでのみ値が正常です)。 . 変数は、マスター ノードで読み込まれます。

さらに、型が定義されているモジュールがあります。


module type_hello_world

type circle_
   real,allocatable  :: straal(:),diameter(:)
end type circle_

end module type_hello_world

私が言ったように、私はこれをより大きなコードから抽象化したので、このモジュールは役に立たないように見えるかもしれませんが、元のコードでは意味があります。

そして 3 番目として、派生データ型のブロードキャストの変位を計算するサブルーチンを含むモジュール ..... http://ladon.iqfr.csic.es/docs/MPI_ug_in_FORTRAN.pdfから Fortran の MPI ユーザー ガイドに従いました。


module create_mpi_types

contains

subroutine build_derived_circle(circle,mesg_mpi_circle)

use type_hello_world

implicit none


include 'mpif.h'


type(circle_),intent(in)     :: circle

! local
integer,parameter       :: number=2
integer                 :: ierr, i
integer             :: block_lengths(number)
integer                 :: displacements(number)
integer                 :: address(number+1)
integer                 :: typelist(number)


!output
integer,intent(out) :: mesg_mpi_circle

!----------------------------------------

!  first specify the types
typelist(1)=MPI_REAL
typelist(2)=MPI_REAL

! specify the number of elements of each type
block_lengths(1)=size(circle%straal)
block_lengths(2)=size(circle%diameter)

! calculate displacements relative to refr. 
call MPI_Address(circle,address(1),ierr)
call MPI_Address(circle%straal,address(2),ierr)
call MPI_Address(circle%diameter,address(3),ierr)

do i = 1, number
    displacements(i)=address(i+1)-address(i)
enddo

! build the derived data type
call MPI_TYPE_STRUCT(number,block_lengths,displacements,&
                    typelist,mesg_mpi_circle,ierr)
! commit it to the system, so it knows we ll use it 
! for communication
call MPI_TYPE_COMMIT(mesg_mpi_circle,ierr)

return

end subroutine build_derived_circle

!------------- END SUBROUTINE----------------------------
end module create_mpi_types

セットアップ用: コードは、Intel fortran でコンパイルされた CentOs6 の下の ETH Brutus クラスターで実行することを目的としています。ただし、同じ問題が発生するいくつかのマシンでテストしたため、バージョンの問題ではないと思います。

4

1 に答える 1

0

バージョンの問題ではありません。簡単に言えば、MPI は割り当て可能な配列を持つ型を好まないということです。これは、この問題と同じです。ポインターと仮想メモリアドレスに関係しています。引用された回答は、本当に必要な場合の方法を示しています。ただし、可能であれば、以下に概説する方法 2 で行います。

これには 2 つの方法があります。1) 内に固定長配列を作成するtype_hello_world

type circle_
   real :: straal(100)
   real :: diameter(100)
end type circle_

2)circle要素を 1 つだけ持つ型を作成し、円の配列を作成します。

type circle_
   real :: straal
   real :: diameter
end type circle_

私は2番目の方法を好みます。変位は MPI_ADDRESS_KIND 型でなければならないことにも注意してください。したがって、コードは次のように変更さcreate_mpi_typesれます

module create_mpi_types

contains

subroutine build_derived_circle(mesg_mpi_circle)

use type_hello_world
use mpi

implicit none


! local
type(circle_)                  :: circle
integer,parameter              :: number=2
integer                        :: ierr, i
integer                        :: block_lengths(number)
integer(kind=MPI_ADDRESS_KIND) :: displacements(number)
integer                        :: typelist(number)
real                           :: r

!output
integer,intent(out) :: mesg_mpi_circle

!----------------------------------------

do i = 0, number
    typelist(i) = MPI_REAL
    block_lengths(i) = 1
    displacements(i) = i * sizeof(r)
enddo
! build the derived data type
call MPI_Type_create_struct(number,block_lengths,displacements,&
                typelist,mesg_mpi_circle,ierr)
if (ierr /= 0 ) then
    print *, 'got an error in type create: ', ierr
    call MPI_Abort(MPI_COMM_WORLD, ierr, ierr)
endif

! commit it to the system, so it knows we ll use it
! for communication
call MPI_TYPE_COMMIT(mesg_mpi_circle,ierr)
if (ierr /= 0 ) then
    print *, 'got an error in type commit: ', ierr
    call MPI_Abort(MPI_COMM_WORLD, ierr, ierr)
endif

return

end subroutine build_derived_circle

!------------- END SUBROUTINE----------------------------
end module create_mpi_types

そして、それを使用するにはhello_world

include 'hello_types.f90'
include 'mpi_circle.f90'

program hello_world

use mpi
use type_hello_world
use create_mpi_types

implicit none

integer                    :: ierr, num_procs, my_id, mpi_circle_t
type(circle_), allocatable :: circles(:)

call MPI_Init(ierr)

!find out MY process ID, and how many processes were started.

call MPI_COMM_RANK (MPI_COMM_WORLD, my_id, ierr)
call MPI_COMM_SIZE (MPI_COMM_WORLD, num_procs, ierr)

allocate(circles(num_procs))

if (my_id==0) then
    !print*,'enter straal and diameter'
    !read*,circle%diameter(1),circle%straal(1)
    circles(:)%diameter = 10.0
    circles(:)%straal = 2.0
endif

call build_derived_circle(mpi_circle_t)

call MPI_BCAST(circles,num_procs,mpi_circle_t,0,MPI_COMM_WORLD,ierr)

print *, "Hello world! I'm process ", my_id, " out of", num_procs, " processes."
print*,my_id,circles(my_id+1)%diameter,circles(my_id+1)%straal

call MPI_TYPE_FREE(mpi_circle_t, ierr)
deallocate(circles)

call MPI_Finalize(ierr)
于 2013-04-05T00:51:20.637 に答える