在我的程序中,我让每个处理器计算一个自定义类型的数组" point"它由4个双精度值和3个双复值组成。我现在希望每个处理器发送它的数组" point"类型到主处理器。
我无法理解如何使用MPI_type命令发送自定义类型。特别是在"点"中具有双重复杂精度。类型。据我所知,MPI没有MPI_DOUBLE_COMPLEX类型。
PROGRAM hello
use mpi
IMPLICIT NONE
INTEGER, PARAMETER :: dp = REAL(KIND(0.0D0))
type point
sequence
real(kind=dp) :: x, y, z, w
double complex :: ex, ey, ez
end type point
type(point), dimension(:), allocatable :: my_points
...
if(rank .ne. master) then
call MPI_SEND(my_points, count, [point?], master, 7, MPI_COMM_WORLD, ierror)
end if
....
END
答案 0 :(得分:4)
MPI标准规定(MPI 2.2规范中的§3.2.2):
MPI需要支持这些数据类型,这些数据类型与Fortran和ISO C的基本数据类型相匹配。如果主机语言具有其他数据类型,则应提供其他MPI数据类型:Fortran中的双精度复杂的MPI_DOUBLE_COMPLEX声明为类型{{ 1}}; ...
至于数据类型的构造,它的工作原理如下。首先,声明一个类型的虚拟双元素数组或(简单地使用已经分配的数组)与DOUBLE COMPLEX
组合以获取每个字段的地址:
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
下一步是构建MPI数据类型本身:
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
(注意:此代码假定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
可以提交,然后用于发送自定义类型的单个元素,但它可能不适用于数组。原因是编译器可能在类型的结尾或开头添加填充。 MPI允许显式设置数据类型的范围。要做到这一点,首先要确定应该有的实际范围:
point_type0
(这应该清楚为什么你需要一个双元素的虚拟数组)
现在将点数据类型“调整”为真实范围并提交结果数据类型:
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
不是第一个组件,它之前的组件也只会有负偏移。