Fortran语言MPI程序设计

导读:indexI是从2到NTOTAL-1。在切割后,只有CPU0是从2开始,其他的CPU都是从istart开始,所以必须设一个变数istart2来解决这个问题:ISTART2=ISTARTIF(MYID.EQ.0)ISTART2=2而loop的终点只有最后一个CPU是到NTOTAL-1,也就是iend-1,其他的CPU都是到iend,所以必须再设一个变数iend

Fortran语言MPI程序设计

index I是从2到NTOTAL-1。在切割后,只有CPU0是从2开始,其他的CPU都是从istart开始,所以必须设一个变数istart2来解决这个问题 :

ISTART2=ISTART

IF(MYID.EQ.0) ISTART2=2

而loop的终点只有最后一个CPU是到NTOTAL-1,也就是iend-1,其他的CPU 都是到iend,所以必须再设一个变数iend1来解决这个问题 :

IEND1=IEND

IF(MYID.EQ.NPROC-1) IEND1=IEND-1

当A(I)的I等于istart时,要用到B(ISTART-1)。而当A(I)的I等于iend 时,要用到 B(IEND+1),所以还必须设一个变数istartm1 (istart minus 1) 和iendp1 (iend plus 1) 来解决这B变数的index问题 :

ISTARTM1=ISTART-1 IENDP1=IEND+1

在需要域外资料 (I-1或I+1等) 的DO loop之前就要叫用MPI_SENDRECV来取得该项资料。不过在这之前先要知道该CPU的左邻右舍是那一个CPU,副程式STARTEND在切割阵列的 index时是把第一段分给CPU0,第二段分给CPU1,第三段分给CPU2,余类推。所以一个CPU的左邻L_NBR就是该CPU的CPU id减一,而其右邻R_NBR就是该CPU的CPU id加一。只有第一个和最后一个CPU是例外,第一个CPU没有左邻,而最后一个CPU没有右邻,这时的左邻右舍就要给他一个特定的名子叫做MPI_PROC_NULL。这个MPI_PROC_RULL是在mpif.h 档里已经设定的常数。

L_NBR=MYID-1 R_NBR=MYID+1

IF(MYID.EQ.0) L_NBR=MPI_PROC_NULL IF(MYID.EQ.NPROC-1) R_NBR=MPI_PROC_NULL

现在来解决B(I-1) 和B(I+1) 的边界资料交换问题,这需要两个MPI_SENDRECV,一个解决B(I-1) 的资料交换,另外一个解决B(I+1) 的资料交换。

先来解决B(I-1) 的边界资料交换问题。从图3.2中的CPU1来看,它要送B(IEND) 给右邻 \当作右邻的B(ISTARTM1)\,又要自左邻取得 \左邻的B(IEND)\做为它自己的

B(ISTARTM1)。如果要传送的对象是MPI_PROC_NULL时,是没有传送动作发生的。每一个CPU 都做同样的动作,就解决了B(ISTARTM1) 的边界资料交换问题。也就是 :

ITAG=110

CALL MPI_SENDRECV (B(IEND), 1, MPI_REAL8, R_NBR, ITAG, 1 B(ISTARTM1), 1, MPI_REAL8, L_NBR, ITAG, 2 MPI_COMM_WORLD, ISTATUS, IERR)

再来解决B(I+1) 的边界资料交换问题。从图3.2中的CPU1来看,它要送B(ISTART) 给左邻 \当作左邻的B(IENDP1)\,又要自右邻取得 \右邻的B(ISTART)\做为它自己的B(IENDP1)。如果要传送的对象是MPI_PROC_NULL时,是没有传送动作发生的。每一个CPU 都做同样的动作,就解决了B(IENDP1) 的边界资料交换问题。也就是 :

ITAG=120

CALL MPI_SENDRECV (B(ISTART), 1, MPI_REAL8, L_NBR, ITAG, 1 B(IENDP1), 1, MPI_REAL8, R_NBR, ITAG, 2 MPI_COMM_WORLD, ISTATUS, IERR)

现在,每一个CPU执行的DO loop范围是从1到N,所以算出来的AMAX是A阵列NTOTAL 个元素里NP分之一个阵列元素的最大值,只是部份资料的最大值。所以此处叫用

MPI_ALLREDUCE找出各个CPU辖区里的最大值AMAX之中的最大值GMAX (global maximum),存放在每一个CPU里。

CALL MPI_ALLREDUCE ( AMAX, GMAX, 1, MPI_REAL8, MPI_MAX, 1 MPI_COMM_WORLD, IERR )

至于甚幺时候使用reduce,甚幺时候使用allreduce,视需要而定。每一个CPU都要用到reduce的结果时就要用MPI_ALLREDUCE,只有一个CPU需要用到reduce 的结果时只要用 MPI_REDUCE就可以了,因为MPI_ALLREDUCE比较耗时间。

所以完整的边界资料交换并行程式如下 :

PROGRAM T3CP

C

C Boundary data exchange without data partition

C Using MPI_SEND, MPI_RECV to distribute input data C

PARAMETER (NTOTAL=200) INCLUDE 'mpif.h'

REAL*8 A(NTOTAL), B(NTOTAL), C(NTOTAL), D(NTOTAL), AMAX, GMAX

INTEGER NPROC, MYID, ISTATUS(MPI_STATUS_SIZE), ISTART, IEND,

1 L_NBR, R_NBR,

2

GSTART(0:31), GEND(0:31), GCOUNT(0:31)

CALL MPI_INIT (IERR)

CALL MPI_COMM_SIZE (MPI_COMM_WORLD, NPROC, IERR) CALL MPI_COMM_RANK (MPI_COMM_WORLD, MYID, IERR) CALL STARTEND (NPROC, 1, NTOTAL, GSTART, GEND,GCOUNT) ISTART=GSTART(MYID) IEND=GEND(MYID)

PRINT *,' NPROC,MYID,ISTART,IEND=', NPROC,MYID,ISTART,IEND

ISTARTM1=ISTART-1 IENDP1=IEND+1 ISTART2=ISTART

IF(MYID.EQ.0) ISTART2=2 IEND1=IEND

IF(MYID.EQ.NPROC-1) IEND1=IEND-1 C

L_NBR=MYID-1 R_NBR=MYID+1

IF(MYID.EQ.0) L_NBR=MPI_PROC_NULL IF(MYID.EQ.NPROC-1) R_NBR=MPI_PROC_NULL C

IF(MYID.EQ.0) THEN

OPEN(7,FILE='input.dat',STATUS='OLD',FORM='UNFORMATTED') READ (7) B READ (7) C READ (7) D

DO IDEST=1,NPROC-1

ISTART1=GSTART(IDEST) KOUNT1=GCOUNT(IDEST) ITAG=10

CALL MPI_SEND ( B(ISTART1), KOUNT1, MPI_REAL8, IDEST, 1 ITAG, MPI_COMM_WORLD, IERR) ITAG=20

CALL MPI_SEND (C(ISTART1), KOUNT1, MPI_REAL8, IDEST, 1 ITAG, MPI_COMM_WORLD, IERR) ITAG=30

CALL MPI_SEND (D(ISTART1), KOUNT1, MPI_REAL8, IDEST, 1 ITAG, MPI_COMM_WORLD, IERR) ENDDO ELSE

KOUNT=(IEND-ISTART+1) ISRC=0 ITAG=10

CALL MPI_RECV (B(ISTART), KOUNT, MPI_REAL8, ISRC, ITAG, 1 MPI_COMM_WORLD, ISTATUS, IERR) ITAG=20

CALL MPI_RECV (C(ISTART), KOUNT, MPI_REAL8, SRC, ITAG, 1 MPI_COMM_WORLD, ISTATUS, IERR) ITAG=30

CALL MPI_RECV (D(ISTART), KOUNT, MPI_REAL8, ISRC, ITAG, 1 MPI_COMM_WORLD, ISTATUS, IERR) ENDIF C

C Exchange data outside the territory C

ITAG=110

CALL MPI_SENDRECV (B(IEND), 1, MPI_REAL8, R_NBR, ITAG, 1 B(ISTARTM1), 1, MPI_REAL8, L_NBR, ITAG, 2 MPI_COMM_WORLD, ISTATUS, IERR) ITAG=120

CALL MPI_SENDRECV (B(ISTART), 1, MPI_REAL8, L_NBR, ITAG, 1 B(IENDP1), 1, MPI_REAL8, R_NBR, ITAG, 2 MPI_COMM_WORLD, ISTATUS, IERR) C

C Computate, gather and write out the computed result C

AMAX=-1.0D12 CCC DO I=2,NTOTAL-1 DO I=ISTART2,IEND1

A(I)=C(I)*D(I)+(B(I-1)+2.0*B(I)+B(I+1))*0.25 AMAX=MAX(AMAX,A(I)) ENDDO ITAG=110

IF(MYID.NE.0) THEN

KOUNT=(IEND-ISTART+1)

IDEST=0

CALL MPI_SEND (A(ISTART), KOUNT, MPI_REAL8, IDEST, ITAG, 1 MPI_COMM_WORLD, IERR)

ELSE

DO ISRC=1,NPROC-1

ISTART1=GSTART(ISRC) KOUNT1=GCOUNT(ISRC)

CALL MPI_RECV (A(ISTART1), KOUNT1, MPI_REAL8, ISRC, ITAG, 1 MPI_COMM_WORLD, ISTATUS, IERR) ENDDO

ENDIF

CALL MPI_ALLREDUCE (AMAX, GMAX, 1, MPI_REAL8, MPI_MAX, 1 MPI_COMM_WORLD, IERR) IF(MYID.EQ.0) THEN

WRITE(*,101) (A(I),I=1,NTOTAL,5) WRITE(*,102) GMAX ENDIF

101 FORMAT(10F8.3)

102 FORMAT('MAXIMUM VALUE of ARRAY A is', E15.5) CALL MPI_FINALIZE(IERR) STOP END

五星文库wxphp.com包含总结汇报、资格考试、IT计算机、办公文档、计划方案、文档下载、旅游景点、word文档、党团工作以及Fortran语言MPI程序设计等内容。

本文共10页1<<8910