Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Struct 为fortran多态派生类型创建MPI_Type_结构_Struct_Fortran_Mpi_Derived Types - Fatal编程技术网

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