mpi_gather不会返回具有fortran派生数据类型的整个向量

时间:2015-03-18 21:56:28

标签: fortran mpi openmpi derived-types

我遇到了一个问题,其中mpi_gather只返回我尝试传递的向量的一小部分。注意,我用np 1运行它,但它也发生在np 2和np 3. NAT = 3(nat =原子数),并且有194个唯一对。

为了实现这一点,我在fortran中有两个派生数据类型:

type dtlrdh_lut
    sequence
    integer p
    integer q
    integer ind
    real(dp), dimension(3, 3) :: TLR
    real(dp), dimension(3, 3, 3, 3) :: dTLRdh
end type dtlrdh_lut

在我的子程序中,我已经定义了我的变量:

    type(dtlrdh_lut), dimension(:), allocatable :: my_dtlrdh, collected_dtlrdh
    integer :: dh_dtype, dr_dtype, dh_types(5), dr_types(6), dh_blocks(5), dr_blocks(6)
    INTEGER(kind=MPI_ADDRESS_KIND) :: dh_offsets(5), dr_offsets(6)
    integer :: numtasks, rank, ierr, dh_displs(nproc_image), dr_displs(nproc_image)
    integer :: n, status(mpi_status_size)

我在另一个方法中拆分进程之间的工作,然后计算需要计算的查找表的元素数,并在这个特定节点上分配本地查找表,如下所示:

    my_num_pairs = 0
    do i = 1, num_pairs, 1
        if(unique_pairs(i)%cpu.eq.me_image) then
            my_num_pairs = my_num_pairs + 1
            end if
        end do
    if(.not.allocated(my_dtlrdh))    allocate(my_dtlrdh(my_num_pairs))

我还将查找表分配并归零,以便将所有内容组合回来,并使用以下代码:         if(me_image.eq.root_image)然后             if(.not.allocated(gather_dtlrdh))allocate(gather_dtlrdh(num_pairs))

        do i=1,my_num_pairs,1
            collected_dtlrdh(i)%p = 0
            collected_dtlrdh(i)%q = 0
            collected_dtlrdh(i)%ind = 0
            collected_dtlrdh(i)%TLR = 0.0_DP
            collected_dtlrdh(i)%dTLRdh = 0.0_DP
            end do
        end if

然后我填写查找表,但我会跳过该代码。它很长而且不相关。完成此操作后,现在是时候启动MPI流程来收集根进程。

    call mpi_get_address(my_dtlrdh(1)%p,               dh_offsets(1), ierr)
    call mpi_get_address(my_dtlrdh(1)%q,               dh_offsets(2), ierr)
    call mpi_get_address(my_dtlrdh(1)%ind,             dh_offsets(3), ierr)
    call mpi_get_address(my_dtlrdh(1)%TLR(1,1),        dh_offsets(4), ierr)
    call mpi_get_address(my_dtlrdh(1)%dTLRdh(1,1,1,1), dh_offsets(5), ierr)
    do i = 2, size(dh_offsets)
      dh_offsets(i) = dh_offsets(i) - dh_offsets(1)
    end do
    dh_offsets(1) = 0
    dh_types = (/MPI_INTEGER, MPI_INTEGER, MPI_INTEGER, MPI_DOUBLE_PRECISION, MPI_DOUBLE_PRECISION/)
    dh_blocks = (/1, 1, 1, 3*3, 3*3*3*3/)
    call mpi_type_struct(5, dh_blocks, dh_offsets, dh_types, dh_dtype, ierr)
    call mpi_type_commit(dh_dtype, ierr)

然后我通过以下方式打电话给:

    call mpi_gather(my_dtlrdh, my_num_pairs, dh_dtype, &
                     collected_dtlrdh, my_num_pairs, dh_dtype, &
                     root_image, intra_image_comm, ierr)

在我收集之后,我可以打印出一切应该是什么样的:

    do i = 1, num_pairs, 1
        write(stdout, *) my_dtlrdh(i)%p, collected_dtlrdh(i)%p, my_dtlrdh(i)%q, collected_dtlrdh(i)%q
        end do

这是我看到非常奇怪的信息的地方。打印出来的前几个元素看起来很好:

       1           1           3           3
       1           1           6           6
       1           1           9           9

但是我的向量的尾端看起来像我只发送174个元素而不是完整的194:

      17           0          24           0
      18           0          19           0
      18           0          20           0
      18           0          21           0
      18           0          22           0

鉴于有194对,并且num_pairs和my_num_pairs都等于194,我感到很困惑。我开始在绝望中开始玩游戏,并发现如果我使用这个聚集调用而不是上面的那个,我得到了完整的向量:

    num_pairs = 2*num_pairs+40
    call mpi_gather(my_dtlrdh, num_pairs, dh_dtype, &
                     collected_dtlrdh, num_pairs, dh_dtype, &
                     root_image, intra_image_comm, ierr)

我发现只是猜测并检查。虽然这可能适用于这个小型测试系统,但它似乎不是一个可扩展的解决方案。我完全不知所措......有什么想法吗?如果您需要我提供更多信息,请告诉我。

2 个答案:

答案 0 :(得分:1)

MPI_TYPE_STRUCT 已弃用,支持MPI_TYPE_CREATE_STRUCT。后者在概念上采用与前者相同的参数,但偏移数组的类型为INTEGER(KIND=MPI_ADDRESS_KIND),即MPI_GET_ADDRESS返回的类型。

答案 1 :(得分:0)

在使用MPI数据类型的数组时,您还应该考虑对齐问题,因为尽管有SEQUENCE属性,编译器可能会在末尾添加一些字节来填充派生类型。因此,根据通过MPI_TYPE_CREATE_RESIZED()子例程应用于my_dtlrdh(1)和my_dtlrdh(2)的MPI_GET_ADDRESS()输出之间的差异来调整dh_dtype的大小是个好主意。

第47页的lecture on datatypes解释了这一点

然而,这可能不足以解释您的问题。