在Fortran 90中具有派生数据类型的MPI.广播问题 [英] MPI with derived data types in Fortran 90. Broadcast trouble

查看:97
本文介绍了在Fortran 90中具有派生数据类型的MPI.广播问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

一段时间以来,我一直在使用使用模块,派生数据类型和MPI的Fortran 90代码.

I am stuck since a while with a Fortran 90 code that uses modules, derived data types and MPI.

我的问题是,在广播派生的数据类型之后,只有主节点的变量具有正确的值,所有其他节点上的变量都不包含应有的值.我从较大的代码中提取了一个最小的示例.它包含主程序:

The problem I have is that after broadcasting the derived data types, only the variables of the master node have the correct values, the variables on all other nodes don't contain what they should. I abstracted a minimal example from our larger code. It contains the main program:

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


输出包含两个打印语句,其中第一个仅打印proc_id(工作正常),第二个打印出相应节点上的变量(这是我有问题的地方,仅在主节点上有值)很好).变量通过在主节点上的读入获得.


The output contains two print statements, where the first one just prints the proc_id (which works fine) and the second prints out the variables on the respective node (This is where i have the problem, only on the master node the values are fine). The variables come via read in on the master node.

还有一个模块,其中定义了类型:

Further there is a module where the type is defined:

module type_hello_world

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

end module type_hello_world


正如我所说,我是从较大的代码中抽象出来的,因此该模块似乎没有用,但在原始代码中是有意义的.


As I said, I abstracted this from a larger code, so this module may seems useless but makes sense in the original code.

第三个模块包含一个子例程,该子例程为导出派生数据类型的广播计算位移. 我从 http://ladon.iqfr.csic.es/遵循了Fortran的MPI用户指南. docs/MPI_ug_in_FORTRAN.pdf

And as third a module that contains a subroutine to calculate displacements for the broadcast of derived data types ..... I followed the MPI Users guide for Fortran from http://ladon.iqfr.csic.es/docs/MPI_ug_in_FORTRAN.pdf

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集群上运行.但是,我们在遇到相同问题的某些计算机上对其进行了测试,因此我认为这不是版本问题.


For the setup: The code is intended to run on the ETH Brutus cluster under CentOs6 compiled with Intel fortran. However we tested it on some machines getting the same problem, so I don't think it is a version problem.

推荐答案

这不是版本问题.简短的答案是MPI不喜欢带有可分配数组的类型.这与此问题相同.它与指针和虚拟内存地址有关,引用的答案显示了您的实际操作方法.但是,如果可能的话,我将通过下面概述的方法2来做到这一点.

It is not a version problem. The short answer is MPI does not like types with allocatable arrays. This is the same as this problem. It has to do with pointers and virtual memory addresses, the cited answer shows you how to do it if you really wanted. However if possible I would do it by method number 2 outlined below.

有两种可能的方法. 1)在type_hello_world

There are two possible ways of doing this. 1) Create fixed length arrays within type_hello_world

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

2)创建一个仅包含一个元素的circle类型,然后创建一个圆形数组.

2) Create a type of circle with only one element, then create an array of circles.

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

我更喜欢第二种方法.还要注意,位移应为MPI_ADDRESS_KIND类型.因此,您的代码将从create_mpi_types更改为

I prefer the second method. Note also that the displacements should be of type MPI_ADDRESS_KIND. So your code would change for create_mpi_types to

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)

这篇关于在Fortran 90中具有派生数据类型的MPI.广播问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆