Struct 为fortran多态派生类型创建MPI_Type_结构
我尝试用Struct 为fortran多态派生类型创建MPI_Type_结构,struct,fortran,mpi,derived-types,Struct,Fortran,Mpi,Derived Types,我尝试用MPI\u Type\u create\u struct构造一个MPI数据类型,以便发送/接收OOP Fortran类型。这种类型看起来像 type :: mytype integer :: id logical :: flag real, allocatable :: x(:) real, allocatable :: y(:) contains procedure, pass :: cto
MPI\u Type\u create\u struct
构造一个MPI数据类型,以便发送/接收OOP Fortran类型。这种类型看起来像
type :: mytype
integer :: id
logical :: flag
real, allocatable :: x(:)
real, allocatable :: y(:)
contains
procedure, pass :: ctor => mytype_ctor
end type
因此,它是一个派生类型,具有可分配数组和类型绑定过程
如何为该类型创建MPI数据类型?
我试了两次,但没有一次成功
第一个变量试图从派生类型mytype
中的类型显式设置类型映射。它使用MPI\u Type\u get\u extent
计算位移。
MPI\u send
和MPI\u recv
在运行时无错误地执行。但是通过write
访问成员数组x
时,会发生运行时错误SIGSEGV
第二个变量使用mytype
的虚拟实例直接读取mytype
成员的起始地址。从我的角度来看,返回的类型映射是毫无意义的。地址在地址空间中分散得很广。发送和接收在运行时不起作用<代码>MPI_发送结果为SIGSEGV
是否有通过MPI传输具有可分配成员和例程的派生类型的标准方法?
我使用mpifort
(verion 18.0.5)编译并运行mpirun-n2
(版本3.1.0)。最简单的例子是以下模块和主程序
module mod
use MPI
implicit none
save
integer :: MPI_mytype_v1
integer :: MPI_mytype_v2
type :: mytype
integer :: id
logical :: flag
real, allocatable :: x(:)
real, allocatable :: y(:)
contains
procedure, pass :: ctor => mytype_ctor
end type
contains
subroutine mytype_ctor(this, nx, ny)
implicit none
class(mytype), intent(inout) :: this
integer, intent(in) :: nx, ny
allocate(this%y(ny))
allocate(this%x(nx))
end subroutine
subroutine MPI_create_mytype_v1(nx,ny)
implicit none
integer, intent(in) :: nx, ny
integer :: types(4), bsize(4)
integer(KIND=MPI_ADDRESS_KIND) :: displacement(4), types_extents(4), lb(4)
integer i, err, rank
bsize = [ 1, 1, nx, ny ]
types = [ MPI_INTEGER, MPI_LOGICAL, MPI_REAL, MPI_REAL ]
do i=1, 4
call MPI_Type_get_extent(types(i), lb(i), types_extents(i), err)
enddo
do i=1, 4
displacement(i) = sum( bsize(1:i-1)*types_extents(1:i-1) )
enddo
call MPI_Comm_rank(MPI_COMM_WORLD, rank, err)
if(rank==0) then
write(*,'(a)' ) 'creation with method 1 - layout'
write(*,'(a,4I5)') 'size ', bsize
write(*,'(a,4I5)') 'type ', types
write(*,'(a,4I5)') 'extnt ', types_extents
write(*,'(a,4I5)') 'displ ', displacement
endif
call MPI_Type_create_struct(4, bsize, displacement, types, MPI_mytype_v1, err)
call MPI_Type_commit(MPI_mytype_v1, err);
end subroutine
subroutine MPI_create_mytype_v2(nx,ny)
implicit none
integer, intent(in) :: nx, ny
type(mytype) :: MTdummy
integer :: types(4), bsize(4)
integer(KIND=MPI_ADDRESS_KIND) :: displacement(4), address(4)
integer i, err, rank
bsize = [ 1, 1, nx, ny ]
types = [ MPI_INTEGER, MPI_LOGICAL, MPI_REAL, MPI_REAL ]
call mytype_ctor(MTdummy, nx,ny)
call MPI_get_Address(MTdummy%id, address(1), err)
call MPI_get_Address(MTdummy%flag, address(2), err)
call MPI_get_Address(MTdummy%x(1), address(3), err)
call MPI_get_Address(MTdummy%y(1), address(4), err)
do i=1, 4
displacement(i) = MPI_Aint_diff(address(i), address(1))
enddo
call MPI_Comm_rank(MPI_COMM_WORLD, rank, err)
if(rank==0) then
write(*,'(a)' ) 'creation with method 2 - layout'
write(*,'(a,4I5)' ) 'size ', bsize
write(*,'(a,4I5)' ) 'type ', types
write(*,'(a,4I25)') 'displ ', displacement
write(*,'(a,4I25)') 'adresses', address
endif
call MPI_Type_create_struct(4, bsize, displacement, types, MPI_mytype_v2, err)
call MPI_Type_commit(MPI_mytype_v2, err);
end subroutine
end module
固定布局看起来像一个合理的类型图
creation with method 1 - layout
size 1 1 3 7
type 7 6 13 13
extnt 4 4 4 4
displ 0 4 8 20
MPI地址查找的布局似乎有问题
creation with method 2 - layout
size 1 1 3 7
type 7 6 13 13
displ 0 4 -140732799234248 -140732798626120
adresses 140732823825384 140732823825388 24591136 25199264
使用第一个变量执行时,数据类型将被发送和接收。写入其成员(以及对成员数组分配的测试x
)会产生:
received id 0
received flag T
is x alloc? T
forrtl: severe (174): SIGSEGV, segmentation fault occurred
我不确定我得到了你想要的-你想要一个单一的MPI派生类型句柄,用于所有mytype类型的变量的实例化吗?如果是这样的话,您会感到失望-MPI句柄实际上是内存中数据布局的句柄,并且由于在实例化之间可能会有所不同,您不能用一个句柄来管理所有这些句柄。在上面的示例中,变量
x
和y
当然总是具有恒定的大小。我在运行时明确告诉MPI它们的大小。因此,如果编译器支持,则类型的内存布局原则上是固定的。如果组件是可分配的,则固定大小并不一定意味着内存中的布局是固定的-如果每次实例化此类类型时都分配x和y,则无法保证它们彼此始终位于相同的地址中。原则上,每种情况都需要一个MPI派生的类型。好吧,这听起来很令人失望。因此,最好的解决方法是将类型的MPI_send和MPI_receive包装起来,并按顺序发送其所有成员,我猜!?或者包装命令,在需要时创建类型并发送。我会分别发送每个成员,但我已经老了,而且陷入了困境。
received id 0
received flag T
is x alloc? T
forrtl: severe (174): SIGSEGV, segmentation fault occurred