MPI 标准规定(MPI 2.2 规范中的第 3.2.2 节):
MPI 需要支持这些数据类型,这些数据类型与 Fortran 和 ISO C 的基本数据类型匹配。如果宿主语言具有其他数据类型,则应提供其他 MPI 数据类型: MPI_DOUBLE_COMPLEX 用于声明为 @987654321 类型的 Fortran 中的双精度复数@; ...
至于数据类型的构造,它是这样工作的。首先,声明一个类型为或(只需使用已分配的)的伪二元数组并结合MPI_GET_ADDRESS获取每个字段的地址:
type(point) :: dummy(2)
integer(kind=MPI_ADDRESS_KIND) :: offsets(7)
integer :: ierr
call MPI_GET_ADDRESS(dummy(1)%x, offsets(1), ierr)
call MPI_GET_ADDRESS(dummy(1)%y, offsets(2), ierr)
call MPI_GET_ADDRESS(dummy(1)%z, offsets(3), ierr)
call MPI_GET_ADDRESS(dummy(1)%w, offsets(4), ierr)
call MPI_GET_ADDRESS(dummy(1)%ex, offsets(5), ierr)
call MPI_GET_ADDRESS(dummy(1)%ey, offsets(6), ierr)
call MPI_GET_ADDRESS(dummy(1)%ez, offsets(7), ierr)
offsets 现在包含绝对地址,因此将它们转换为相对于dummy%x 的偏移量:
integer :: i
do i = 2,7
offsets(i) = offsets(i) - offsets(1)
end do
! dummy%x serves as base address, therefore set the offset to 0
offsets(1) = 0
下一步是自己构造 MPI 数据类型:
integer :: oldtypes(7), lengths(7)
integer :: point_type0
! dummy%x
oldtypes(1) = MPI_DOUBLE_PRECISION
lengths(1) = 1
! dummy%y
oldtypes(2) = MPI_DOUBLE_PRECISION
lengths(2) = 1
! dummy%z
oldtypes(3) = MPI_DOUBLE_PRECISION
lengths(3) = 1
! dummy%w
oldtypes(4) = MPI_DOUBLE_PRECISION
lengths(4) = 1
! dummy%ex
oldtypes(5) = MPI_DOUBLE_COMPLEX
lengths(5) = 1
! dummy%ey
oldtypes(6) = MPI_DOUBLE_COMPLEX
lengths(6) = 1
! dummy%ez
oldtypes(7) = MPI_DOUBLE_COMPLEX
lengths(7) = 1
call MPI_TYPE_CREATE_STRUCT(7, lengths, offsets, oldtypes, point_type0, ierr)
(注意:此代码假定real(kind=KIND(0.0D0)) 实际上是DOUBLE PRECISION)
那时你几乎准备好了。 point_type0 可以提交,然后用于发送自定义类型的单个元素,但它可能不适用于数组。原因是编译器可能会在类型的末尾或开头添加填充。 MPI 允许显式设置数据类型的范围。为此,首先确定应该存在的实际范围:
integer(kind=MPI_ADDRESS_KIND) :: extent
! Reuse the offsets array
call MPI_GET_ADDRESS(dummy(1)%x, offsets(1), ierr)
call MPI_GET_ADDRESS(dummy(2)%x, offsets(2), ierr)
extent = offsets(2) - offsets(1)
(这应该清楚为什么需要一个二元素虚拟数组)
现在将点数据类型“调整”到真实范围并提交结果数据类型:
integer :: point_type
call MPI_TYPE_CREATE_RESIZED(point_type0, 0_MPI_ADDRESS_KIND, extent, &
point_type, ierr)
call MPI_TYPE_COMMIT(point_type, ierr)
现在你可以使用新注册的类型了:
if(rank .ne. master) then
call MPI_SEND(my_points(1)%x, count, point_type, &
master, 7, MPI_COMM_WORLD, ierror)
end if
请注意,第一个数组元素的x 字段是明确给出的。这样做是因为在计算偏移量时使用dummy%x 作为基础。
在您的情况下,上述某些步骤可能不是绝对必要的,因为您有一个序列类型,这可能会阻止编译器对齐字段。尽管如此,始终按照所示方式执行它是一个好主意,因为它既适用于打包类型,也适用于非打包类型。如果类型定义中缺少sequence 语句,则允许编译器以它认为合适的任何顺序存储组件。这没有任何改变,因为即使 dummy%x 不是第一个组件,它之前的组件也只会有负偏移。