mpi_gather 不 return 具有 Fortran 派生数据类型的整个向量

mpi_gather doesn't return entire vector with fortran derived datatype

我 运行 遇到一个问题,其中 mpi_gather 只有 returns 我试图传递的矢量的一小部分。请注意,我是 运行 这与 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)

我用另一种方法拆分了进程之间的工作,然后计算查找 table 需要计算的元素数量,并在这个特定节点上分配本地查找 tables所以:

    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))

我还分配了查找 table 并将其归零,所有内容都将与以下代码组合回去: 如果(me_image.eq.root_image)那么 如果(。not.allocated(collected_dtlrdh))分配(collected_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

然后我填写查询 table,但我将跳过该代码。它很长而且不相关。完成此操作后,就可以启动 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,我很困惑。我继续前进,开始绝望地玩耍,发现如果我使用这个 gather 调用而不是上面的调用,我会得到完整的向量:

    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)

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

MPI_TYPE_STRUCT 弃用 取而代之的是 MPI_TYPE_CREATE_STRUCT。后者在概念上采用与前者相同的参数,但偏移数组的类型为 INTEGER(KIND=MPI_ADDRESS_KIND),即 MPI_GET_ADDRESS.

返回的类型

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

第 41 页 lecture on datatypes 对此进行了解释

但这可能不足以解释您的问题。