我遇到了一个问题,其中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)
我发现只是猜测并检查。虽然这可能适用于这个小型测试系统,但它似乎不是一个可扩展的解决方案。我完全不知所措......有什么想法吗?如果您需要我提供更多信息,请告诉我。
答案 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解释了这一点
然而,这可能不足以解释您的问题。