使用MPI_Gatherv for Fortran

使用MPI_Gatherv for Fortran,mpi,parallel-processing,fortran90,Mpi,Parallel Processing,Fortran90,此问题遵循MPI\u type\u create\u子阵列和MPI\u Gather上的现有线程。我的目标是使用Fortran 90中的MPI_Type_Create_Subarray和MPI_Gatherv,将所有从进程(4个)中较大数组的子数组收集到主进程(秩=0)上的较大数组中。这将帮助我了解其他项目的MPI_Gatherv。以下是我的示例代码: program main implicit none include "mpif.h" integer :: i

此问题遵循MPI\u type\u create\u子阵列和MPI\u Gather上的现有线程。我的目标是使用Fortran 90中的MPI_Type_Create_Subarray和MPI_Gatherv,将所有从进程(4个)中较大数组的子数组收集到主进程(秩=0)上的较大数组中。这将帮助我了解其他项目的MPI_Gatherv。以下是我的示例代码:

    program main
    implicit none
    include "mpif.h"
    integer :: ierr, myRank, nProcs
    integer :: sendsubarray, recvsubarray, resizedrecvsubarray
    integer, dimension(2) :: starts,sizes,subsizes
    integer, dimension(:), allocatable :: counts, disps
    integer, parameter :: nx_glb=10, ny_glb=10, nx=5, ny=5
    integer, dimension(:,:), target, allocatable :: mat, matG
    integer, pointer :: sendPtr(:,:), recvPtr(:,:)
    integer :: i, j

    call mpi_init(ierr)
    call mpi_comm_rank(mpi_comm_world, myRank, ierr)
    call mpi_comm_size(mpi_comm_world, nProcs, ierr)

    sizes(1)=nx+2; sizes(2)=ny+2
    subsizes(1)=nx; subsizes(2)=ny
    starts(1)=2; starts(2)=2
    call mpi_type_create_subarray(2, sizes, subsizes, starts, mpi_order_fortran, &
                                mpi_integer, sendsubarray, ierr)
    call mpi_type_commit(sendsubarray,ierr)

    allocate(mat(1:nx+2,1:ny+2))
    do j=1, ny+2
     do i=1, nx+2
      if(i.eq.1 .or. i.eq.nx+2 .or. j.eq.1 .or. j.eq.ny+2) then
       mat(i,j)=1000
      else
       mat(i,j) = myRank
      end if
     end do
    end do

    sendPtr=>mat
    if(myRank.eq.0) then
     allocate(matG(nx_glb,ny_glb))
     matG=1000
     sizes(1)=nx_glb; sizes(2)=ny_glb
     subsizes(1)=nx; subsizes(2)=ny
     starts(1)=1; starts(2)=1
     call mpi_type_create_subarray(2, sizes, subsizes, starts, mpi_order_fortran, &
                                   mpi_integer, recvsubarray, ierr)
     call mpi_type_commit(recvsubarray, ierr)
     call mpi_type_create_resized(recvsubarray, 1, sizeof(i), resizedrecvsubarray, ierr)
     call mpi_type_commit(resizedrecvsubarray,ierr)
     recvPtr=>matG
    end if

    counts(1:4) = (/1, 1, 1, 1/)
    disps(1:4) = (/0, 5, 50, 55/)
    call mpi_gatherv(sendPtr,1,sendsubarray,recvPtr,counts,disps,resizedrecvsubarray, &
                     0,mpi_comm_world,ierr)

    if(myRank.eq.0) then
     do i=1, nx_glb
      write(1000,*) (matG(i,j),j=1, ny_glb)
     end do
    end if

    call mpi_finalize(ierr)

    end program main
但是,执行此代码会导致出现
forrtl:severe(174):SIGSEGV,分段错误

似乎我试图指向一个数组的变量/位置,该变量/位置在收集时尚未初始化或声明。我尝试了很多方法进行调试,但都没有成功


非常感谢。

当你看到这里的主要问题时,你会自责的;您没有分配计数或显示

另外,我强烈建议使用
使用mpi
而不是
包含mpif.h
;use语句(在隐式none之前)引入了F90接口,它具有更好的类型检查功能。当您这样做时,您还将看到,对于您的类型create resized,您将需要
类型的整数
mpi\u address\u类型

更新

好的,对于如何进行GathereV的更大问题,您基本上是对的,但是您是对的,start、disp等必须为零索引,而不是1索引,因为实际的MPI库是从C的角度进行操作的,即使使用FORTRAN绑定也是如此。因此,对于sendsubarray,开始必须是
[1,1]
;对于recv子阵列,它必须是
[0,0]
,并且resize、start必须是0,extent必须是sizeof(type)(这两者都必须是mpi\u address\u种类的整数)

我附加了一个带有这些更新的代码版本,并且底层数组的类型为character,因此更容易打印诊断并查看发生了什么:

program main
    use mpi
    implicit none
    integer :: ierr, myRank, nProcs
    integer :: sendsubarray, recvsubarray, resizedrecvsubarray
    integer, dimension(2) :: starts,sizes,subsizes
    integer, dimension(:), allocatable :: counts, disps
    integer, parameter :: nx_glb=10, ny_glb=10, nx=5, ny=5
    character, dimension(:,:), target, allocatable :: mat, matG
    character :: c
    integer :: i, j, p
    integer(kind=mpi_address_kind) :: start, extent

    call mpi_init(ierr)
    call mpi_comm_rank(mpi_comm_world, myRank, ierr)
    call mpi_comm_size(mpi_comm_world, nProcs, ierr)

    sizes(1)=nx+2; sizes(2)=ny+2
    subsizes(1)=nx; subsizes(2)=ny
    starts(1)=1; starts(2)=1
    call mpi_type_create_subarray(2, sizes, subsizes, starts, mpi_order_fortran, &
                                mpi_character, sendsubarray, ierr)
    call mpi_type_commit(sendsubarray,ierr)

    allocate(mat(1:nx+2,1:ny+2))
    mat='.'
    forall (i=2:nx+1,j=2:ny+1) mat(i,j)=ACHAR(ICHAR('0')+myRank)

    if(myRank.eq.0) then
     allocate(matG(nx_glb,ny_glb))
     matG='.'
     sizes(1)=nx_glb; sizes(2)=ny_glb
     subsizes(1)=nx; subsizes(2)=ny
     starts(1)=0; starts(2)=0
     call mpi_type_create_subarray(2, sizes, subsizes, starts, mpi_order_fortran, &
                                   mpi_character, recvsubarray, ierr)
     call mpi_type_commit(recvsubarray, ierr)
     extent = sizeof(c)
     start = 0
     call mpi_type_create_resized(recvsubarray, start, extent, resizedrecvsubarray, ierr)
     call mpi_type_commit(resizedrecvsubarray,ierr)
    end if

    allocate(counts(4),disps(4))
    counts(1:4) = (/1, 1, 1, 1/)
    disps(1:4) = (/0, 5, 50, 55/)
    call mpi_gatherv(mat,1,sendsubarray,matG,counts,disps,resizedrecvsubarray, &
                     0,mpi_comm_world,ierr)

    do p=0,nProcs
      if (myRank == p) then
         print *, 'Local array for rank ', myRank
         do i=1, nx+2
          print *, (mat(i,j),j=1,ny+2)
         end do
      endif
      call MPI_Barrier(MPI_COMM_WORLD,ierr)
    enddo
    if(myRank.eq.0) then
     print *, 'Global array: '
     do i=1, nx_glb
      print *, (matG(i,j),j=1, ny_glb)
     end do
    end if

    call mpi_finalize(ierr)

end program main
输出:

 Local array for rank            0
 .......
 .00000.
 .00000.
 .00000.
 .00000.
 .00000.
 .......
 Local array for rank            1
 .......
 .11111.
 .11111.
 .11111.
 .11111.
 .11111.
 .......
 Local array for rank            2
 .......
 .22222.
 .22222.
 .22222.
 .22222.
 .22222.
 .......
 Local array for rank            3
 .......
 .33333.
 .33333.
 .33333.
 .33333.
 .33333.
 .......
 Global array: 
 0000022222
 0000022222
 0000022222
 0000022222
 0000022222
 1111133333
 1111133333
 1111133333
 1111133333
 1111133333
…有道理吗?这与这里回答的这个问题的C版本非常相似(),但您已经基本解决了问题


哦,是的,还有一件事--实际上不需要在Fortran中设置指向发送/接收数据的指针。在C语言中,您需要显式地将指针传递给数据数组;在fortran中,您可以只传递数组(它们已经“通过引用”传递了,例如相当于C向变量传递指针)。因此,您可以直接通过阵列。

当您看到这里的主要问题时,您会踢自己;您没有分配计数或显示

另外,我强烈建议使用
使用mpi
而不是
包含mpif.h
;use语句(在隐式none之前)引入了F90接口,它具有更好的类型检查功能。当您这样做时,您还将看到,对于您的类型create resized,您将需要
类型的整数
mpi\u address\u类型

更新

好的,对于如何进行GathereV的更大问题,您基本上是对的,但是您是对的,start、disp等必须为零索引,而不是1索引,因为实际的MPI库是从C的角度进行操作的,即使使用FORTRAN绑定也是如此。因此,对于sendsubarray,开始必须是
[1,1]
;对于recv子阵列,它必须是
[0,0]
,并且resize、start必须是0,extent必须是sizeof(type)(这两者都必须是mpi\u address\u种类的整数)

我附加了一个带有这些更新的代码版本,并且底层数组的类型为character,因此更容易打印诊断并查看发生了什么:

program main
    use mpi
    implicit none
    integer :: ierr, myRank, nProcs
    integer :: sendsubarray, recvsubarray, resizedrecvsubarray
    integer, dimension(2) :: starts,sizes,subsizes
    integer, dimension(:), allocatable :: counts, disps
    integer, parameter :: nx_glb=10, ny_glb=10, nx=5, ny=5
    character, dimension(:,:), target, allocatable :: mat, matG
    character :: c
    integer :: i, j, p
    integer(kind=mpi_address_kind) :: start, extent

    call mpi_init(ierr)
    call mpi_comm_rank(mpi_comm_world, myRank, ierr)
    call mpi_comm_size(mpi_comm_world, nProcs, ierr)

    sizes(1)=nx+2; sizes(2)=ny+2
    subsizes(1)=nx; subsizes(2)=ny
    starts(1)=1; starts(2)=1
    call mpi_type_create_subarray(2, sizes, subsizes, starts, mpi_order_fortran, &
                                mpi_character, sendsubarray, ierr)
    call mpi_type_commit(sendsubarray,ierr)

    allocate(mat(1:nx+2,1:ny+2))
    mat='.'
    forall (i=2:nx+1,j=2:ny+1) mat(i,j)=ACHAR(ICHAR('0')+myRank)

    if(myRank.eq.0) then
     allocate(matG(nx_glb,ny_glb))
     matG='.'
     sizes(1)=nx_glb; sizes(2)=ny_glb
     subsizes(1)=nx; subsizes(2)=ny
     starts(1)=0; starts(2)=0
     call mpi_type_create_subarray(2, sizes, subsizes, starts, mpi_order_fortran, &
                                   mpi_character, recvsubarray, ierr)
     call mpi_type_commit(recvsubarray, ierr)
     extent = sizeof(c)
     start = 0
     call mpi_type_create_resized(recvsubarray, start, extent, resizedrecvsubarray, ierr)
     call mpi_type_commit(resizedrecvsubarray,ierr)
    end if

    allocate(counts(4),disps(4))
    counts(1:4) = (/1, 1, 1, 1/)
    disps(1:4) = (/0, 5, 50, 55/)
    call mpi_gatherv(mat,1,sendsubarray,matG,counts,disps,resizedrecvsubarray, &
                     0,mpi_comm_world,ierr)

    do p=0,nProcs
      if (myRank == p) then
         print *, 'Local array for rank ', myRank
         do i=1, nx+2
          print *, (mat(i,j),j=1,ny+2)
         end do
      endif
      call MPI_Barrier(MPI_COMM_WORLD,ierr)
    enddo
    if(myRank.eq.0) then
     print *, 'Global array: '
     do i=1, nx_glb
      print *, (matG(i,j),j=1, ny_glb)
     end do
    end if

    call mpi_finalize(ierr)

end program main
输出:

 Local array for rank            0
 .......
 .00000.
 .00000.
 .00000.
 .00000.
 .00000.
 .......
 Local array for rank            1
 .......
 .11111.
 .11111.
 .11111.
 .11111.
 .11111.
 .......
 Local array for rank            2
 .......
 .22222.
 .22222.
 .22222.
 .22222.
 .22222.
 .......
 Local array for rank            3
 .......
 .33333.
 .33333.
 .33333.
 .33333.
 .33333.
 .......
 Global array: 
 0000022222
 0000022222
 0000022222
 0000022222
 0000022222
 1111133333
 1111133333
 1111133333
 1111133333
 1111133333
…有道理吗?这与这里回答的这个问题的C版本非常相似(),但您已经基本解决了问题


哦,是的,还有一件事--实际上不需要在Fortran中设置指向发送/接收数据的指针。在C语言中,您需要显式地将指针传递给数据数组;在fortran中,您可以只传递数组(它们已经“通过引用”传递了,例如相当于C向变量传递指针)。因此,您可以通过阵列。

谢谢Jon。那对我来说真是太傻了。但是,在实现您提到的更改后,我对Fortran的mpi_type_create_子数组的
start
参数有点困惑。现在的代码似乎没有按照我想要的方式工作,因为我已经声明
start
对于
sendsubarray
为2,对于
recvsubarray
为1,这两个值应该分别为1和0。此外,即使是
resize
的下限也应为0。我无法理解C和Fortran之间的区别,因为数组在C中从0开始,而在F90中从1开始。谢谢,好,;听起来我们还没有完全回答你的问题;除了第一个灾难性的错误,我没有看太多。让我仔细看一下……谢谢你,乔恩。我真的很感激。谢谢你,乔恩。那对我来说真是太傻了。但是,在实现您提到的更改后,我对Fortran的mpi_type_create_子数组的
start
参数有点困惑。现在的代码似乎没有按照我想要的方式工作,因为我已经声明
start
对于
sendsubarray
为2,对于
recvsubarray
为1,这两个值应该分别为1和0。此外,即使是
resize
的下限也应为0。我无法理解C和Fortran之间的区别,因为数组在C中从0开始,而在F90中从1开始。谢谢,好,;听起来我们还没有完全回答你的问题;除了第一个灾难性的错误,我没有看太多。让我仔细看一下……谢谢你,乔恩。我会非常感激的。