MPI_TYPE_VECTOR

时间:2016-07-01 14:36:33

标签: fortran mpi

我正在尝试使用MPI_TYPE_VECTOR以便在2D计算域的重影单元之间交换信息。测试用例如下:

拓扑由垂直方向上的两个块和其他方向上的一个块组成。目标是用相邻块的相应单元填充每个块的重影单元。

如果我不使用MPI中的派生类型,通信就可以了。

    PROGRAM test

      USE mpi

      IMPLICIT NONE

      INTEGER*4, PARAMETER :: kim = 3  ! Number of cells (horizontal)
     &     , kjm = 2  ! Number of cells (vertical)
     &     , is  = 1  ! Number of ghost cells 

      INTEGER*4, DIMENSION(1-is:kim+is,1-is:kjm+is)
     &     :: vect2d  ! 2D vector representing the computational domain

      INTEGER*4 :: i, j

!     MPI Parameters

      INTEGER*4, PARAMETER :: ndims = 2 
      INTEGER*4 :: mpicode      
      INTEGER*4 :: nb_procs     
      INTEGER*4 :: rank         
      INTEGER*4 :: comm         
      INTEGER*4 :: etiquette = 100 
      INTEGER*4, DIMENSION (ndims) :: dims 
      INTEGER*4, DIMENSION (ndims) :: coords 
      LOGICAL, DIMENSION (ndims) :: periods 
      LOGICAL :: reorganisation 
      INTEGER, DIMENSION(MPI_STATUS_SIZE) :: statut 
      INTEGER*4, DIMENSION (2*ndims) :: neighbors 
      INTEGER*4 :: type_column 

! Initialisation MPI

      CALL MPI_INIT (mpicode)
      CALL MPI_COMM_SIZE (MPI_COMM_WORLD, nb_procs, mpicode)
      CALL MPI_COMM_RANK (MPI_COMM_WORLD, rank, mpicode)

      dims(1) = 1
      dims(2) = 2

      periods = .FALSE.
      reorganisation = .FALSE.

      CALL MPI_CART_CREATE (MPI_COMM_WORLD, ndims, dims, periods,
     &     reorganisation, comm, mpicode)
      CALL MPI_CART_COORDS (comm, rank, ndims, coords, mpicode)

      CALL MPI_CART_SHIFT (comm, 0, 1, neighbors(1), neighbors(2),
     &     mpicode)
      CALL MPI_CART_SHIFT (comm, 1, 1, neighbors(3), neighbors(4),
     &     mpicode)

! Initialisation domain

      DO i = 1-is, kim+is
         DO j = 1-is, kjm +is

            vect2d(i,j) = rank

         END DO
      END DO

! Communications
!     Without vector type

      DO i = 1, kim

           CALL MPI_RECV (vect2d(i,1-is:0),
     &         size(vect2d(i,1-is:0)),
     &         MPI_INTEGER, neighbors(3), etiquette, comm,
     &         statut, mpicode)

           CALL MPI_SEND (vect2d(i,kjm+1-is:kjm),
     &          size(vect2d(i,kjm+1-is:kjm)),
     &          MPI_INTEGER, neighbors(4), etiquette, comm,
     &          mpicode)

           CALL MPI_RECV (vect2d(i,kjm+1:kjm+is),
     &          size(vect2d(i,kjm+1:kjm+is)),
     &          MPI_INTEGER, neighbors(4), etiquette, comm,
     &          statut, mpicode)

           CALL MPI_SEND (vect2d(i,1:is),
     &          size(vect2d(i,1:is)),
     &          MPI_INTEGER, neighbors(3), etiquette, comm,
     &          mpicode)

        END DO

! Write


      OPEN (10,
     &     file = "test.dat",
     &     form = "formatted",
     &     status = "unknown")

      IF (rank .EQ.1 ) WRITE(10,*) vect2D

      CLOSE(10)

      CALL MPI_FINALIZE(mpicode)

      END PROGRAM test

在这种情况下,上部块的第一行是[10001],因此重影单元用下部块的值填充。

使用MPI_TYPE_VECTOR

      PROGRAM test

      USE mpi

      IMPLICIT NONE

      INTEGER*4, PARAMETER :: kim = 3  ! Number of cells (horizontal)
     &     , kjm = 2  ! Number of cells (vertical)
     &     , is  = 1  ! Number of ghost cells 

      INTEGER*4, DIMENSION(1-is:kim+is,1-is:kjm+is)
     &     :: vect2d  ! 2D vector representing the computational domain

      INTEGER*4 :: i, j

!     MPI Parameters

      INTEGER*4, PARAMETER :: ndims = 2 
      INTEGER*4 :: mpicode      
      INTEGER*4 :: nb_procs     
      INTEGER*4 :: rank         
      INTEGER*4 :: comm         
      INTEGER*4 :: etiquette = 100 
      INTEGER*4, DIMENSION (ndims) :: dims 
      INTEGER*4, DIMENSION (ndims) :: coords 
      LOGICAL, DIMENSION (ndims) :: periods 
      LOGICAL :: reorganisation 
      INTEGER, DIMENSION(MPI_STATUS_SIZE) :: statut 
      INTEGER*4, DIMENSION (2*ndims) :: neighbors 
      INTEGER*4 :: type_column 

!------------------------------------------------------------------------------
! Initialisation MPI

      CALL MPI_INIT (mpicode)
      CALL MPI_COMM_SIZE (MPI_COMM_WORLD, nb_procs, mpicode)
      CALL MPI_COMM_RANK (MPI_COMM_WORLD, rank, mpicode)

      dims(1) = 1
      dims(2) = 2

      periods = .FALSE.
      reorganisation = .FALSE.

      CALL MPI_CART_CREATE (MPI_COMM_WORLD, ndims, dims, periods,
     &     reorganisation, comm, mpicode)
      CALL MPI_CART_COORDS (comm, rank, ndims, coords, mpicode)

      CALL MPI_CART_SHIFT (comm, 0, 1, neighbors(1), neighbors(2),
     &     mpicode)
      CALL MPI_CART_SHIFT (comm, 1, 1, neighbors(3), neighbors(4),
     &     mpicode)

      CALL MPI_TYPE_VECTOR(is, 1, (kim+2*is),
     &     MPI_INTEGER, type_column, mpicode)

      CALL MPI_TYPE_COMMIT(type_column, mpicode)

!------------------------------------------------------------------------------
! Initialisation domain

      DO i = 1-is, kim+is
         DO j = 1-is, kjm +is

            vect2d(i,j) = rank

         END DO
      END DO

!------------------------------------------------------------------------------
! Communications

!     With vector type

      DO i = 1, kim

         CALL MPI_RECV (vect2d(j,1-is),
     &        1,
     &        type_column, neighbors(3), etiquette, comm,
     &        statut, mpicode)

         CALL MPI_SEND (vect2d(i,kjm+1-is),
     &        1,
     &        type_column, neighbors(4), etiquette, comm,
     &        mpicode)


         CALL MPI_RECV (vect2d(i,kjm+1),
     &        1,
     &        type_column, neighbors(4), etiquette, comm,
     &        statut, mpicode)

         CALL MPI_SEND (vect2d(i,1),
     &        1,
     &        type_column, neighbors(3), etiquette, comm,
     &        mpicode)

       END DO


!------------------------------------------------------------------------------
! Write


      OPEN (10,
     &     file = "test.dat",
     &     form = "formatted",
     &     status = "unknown")

      IF (rank .EQ.1 ) WRITE(10,*) vect2D

      CLOSE(10)

      CALL MPI_FINALIZE(mpicode)

      END PROGRAM test

在这种情况下,输出不是预期的输出,因为我得到:[11110] 我想这是我的type_column的定义,但我无法弄明白......所以欢迎任何帮助和解释!

谢谢

编辑:这是与测试用例中的矩阵相关联的域

(0,3)| (1,3)| (2,3)| (3,3)| (4,3)

(0,2)| (1,2)| (2,2)| (3,2) | (4,2)

(0,1)| (1,1)| (2,1)| (3,1) | (4,1)

(0,0)| (1,0)| (2,0)| (3,0)| (4,0)

根据我的理解,与此矩阵相关的记忆处置是:

(0,0)| (1,0)| (2,0)| (3,0)| (4,0) | (0,1)| (1,1)| (2,1)| (3,1) | (4,1) ......

1 个答案:

答案 0 :(得分:1)

这里的主要困惑是您使用了术语“列”,但是绘制数组的方式意味着您实际上正在交换行。让我们坚持你的绘制数组的约定,并调用方向“水平”(增加第一个索引“i”的值)和“垂直”(增加第二个索引“j”的值),以避免混淆。

如果我们修复您的i< - >在评论中提到的j bug然后你的代码工作。但是,关于使用向量的重点是避免多次发送,因此,如上所述,使用基本数据类型时,向量代码不会改进。对于上面显示的模式,至少对于单深度光环,您可以使用count = kim发送连续数据。对于更深的晕圈,你需要一个矢量类型,其中count = is,blocksize = kim和stride = kim + 2 * is。完成此操作后,您将在发送和接收时使用count = 1,并通过一次调用传输所有光环。

对于水平方向上的光环交换(即交换垂直光晕),你总是需要一个count = kjm,blocksize = is和stride = km + 2 *的矢量类型。再次,在发送和接收时使用count = 1.

首先发出receive(周期性边界条件的潜在死锁)还有其他问题,这些问题不能通过先发送(因为MPI_Send可以同步实现)来完全解决,但对于您的特定测试代码,解决方案在于与术语一致并使用适当的矢量类型。