F90中的MPI_GATHER / MPI_GATHERV存在导出数据类型的问题

时间:2016-04-12 01:24:41

标签: mpi fortran90

我有一项任务,我将在一起拥有多种数据类型;字符,几个整数和双精度值,它们代表问题的解决方案。

目前,我有一个玩具" F90程序,它使用带有随机数的MPI和每个处理器的人为字符串。我想要一个具有字符和双精度随机数的数据类型。

我将使用MPI_REDUCE来获得双精度值的最小值。我将通过MPI_GATHERV函数将每个进程的数据类型汇总到根(rank = 0)。

我的目标是将随机值中的最小值与数据类型相匹配。那将是最终的答案。到目前为止,我已尝试过各种各样的想法,但无济于事。我最终得到了" forrtl:严重的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

感谢您的帮助。 此致 埃林

1 个答案:

答案 0 :(得分:1)

对于我来说,尝试完全修复它的代码肯定太令人困惑了。因此,我们假设您将类型mytype定义如下:

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

(Rk:我已将len=4添加到y的定义中,因为它似乎在原始代码中缺失。我可能错了,如果是这样,只需调整{{1在相应的后续代码中)

现在让我们假设您只想转移blocklen(2)类型变量的xy字段。为此,您需要使用第一个mytype创建一个适当的派生MPI类型,以定义基本类型及其在结构中的位置,然后MPI_Type_create_struct()来定义真实范围和下限。类型,包括洞。

棘手的部分通常是评估Fortran类型的下限和范围。在这里,当您包含转移第一个和最后一个字段的字段时,以及添加MPI_Type_create_resized()时,您可以使用bind(C)来获取这些信息。但是,如果您未将MPI_Type_get_extend()x(这是该类型的第一个和最后一个字段)包含在MPI数据类型中,y将无法返回您所拥有的内容需要。因此,我会建议您采用另一种(稍微繁琐)的方法,我相信这种方法始终有效:

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的数组的两个连续元素的相对地址计算的。 。
然后,我们创建一个中间MPI数据类型mytype,它只包含有关我们将要传输的实际数据的信息,并将有关Fortran类型的实际下限和范围的信息扩展到tmptypefoo 。最后,只需要提交最后一个,因为它只用于数据传输。