PROGRAM life IMPLICIT NONE ! ! MAXLOOP iterations of an NxN life board ! INTEGER :: N, MAXLOOP INTEGER, ALLOCATABLE, DIMENSION(:,:,:) :: step INTEGER loop, i, j, cr, nx, r, c, nb, ls CHARACTER*(16) name REAL(8) :: wall1, wall2, wall ! ! MPI variables INTEGER :: my_rank=0, numprocs=1, ierr, tag ! INTEGER :: p, my_start, my_end, my_out_col0, my_out_col1, my_cols, loc_out_col0, loc_out_col1 INTEGER :: my_inn_col0, my_inn_col1, loc_inn_col0, loc_inn_col1, istart, iend ! ! MPI initialization ! ! ! Initialization ! IF ( my_rank == 0 ) THEN WRITE(*,*) " N, MaxLoop ?" ! READ*,N,MAXLOOP N = 200; MAXLOOP = 32 ! Allocate full step board ALLOCATE(step(N,N,2), STAT=ierr) IF ( ierr /= 0 ) THEN WRITE(*,*) " Error allocating step(N,N,2)" ierr = -1 CALL Terminate(my_rank,ierr) STOP END IF ! Initialize step step = 0 ! Ten active cells in a line step(N/2,((N/2)-5):((N/2)+4),1) = 1 ! ! Print starting config to file Life0000.pgm ! loop = 0 WRITE(name,"(A4,I4.4)") "Life",loop CALL INTDATA2MPGM(N,N,step(:,:,1),name,4) END IF ! Send initial data to processes IF ( my_rank == 0 ) THEN CALL ProcessBand(N,my_start,my_end,numprocs,my_rank) ! Global columns my_out_col0 = MAX(my_start-1,1) ! First allocated column in global numeration my_out_col1 = MIN(my_end+1,N) ! Last allocated column in global numeration my_inn_col0 = my_out_col0 + 1 my_inn_col1 = my_out_col1 - 1 my_cols = (my_out_col1-my_out_col0+1) ! Total allocated columns ! Send process data ! ELSE ! my_rank > 0 receive data END IF loc_out_col0 = 1 ! First allocated column in local numeration loc_inn_col0 = 2 ! First column to be computed in local numeration loc_out_col1 = loc_out_col0 + my_out_col1 - my_out_col0 loc_inn_col1 = loc_inn_col0 + my_inn_col1 - my_inn_col0 ! Last column to be computed in local numeration ! ! Perform MAXLOOP updates ! DO loop = 1, MAXLOOP cr = 2-mod(loop,2) nx = 2-mod(loop+1,2) ! Send border values IF ( my_end < N ) then ! Send my rightmost column to left border of receiver END IF IF ( my_start > 1 ) then ! Send my leftmost column to right border of receiver END IF ! Acquire border values IF ( my_start > 1 ) then ! Acquire left border END IF IF ( my_end < N ) then ! Acquire right border END IF DO r = 2, N-1 DO c = loc_inn_col0, loc_inn_col1 ! local columns step(r,c,nx) = step(r,c,cr) ! Inizialize cell ! Per each cell nb = 0 DO i = r-1,r+1 DO j = c-1,c+1 ! Count active neighbours IF ( .NOT. (i == r .AND. j == c) ) THEN nb = nb + step(i,j,cr) END IF END DO END DO IF (nb.lt.2 .or. nb.gt.3) THEN step(r,c,nx) = 0 ELSE IF (nb.eq.3) THEN step(r,c,nx) = 1 END IF END DO END DO ! ! Send data to root process ! ! IF ( my_rank == 0 ) THEN ! receives data ! ELSE ! Send data to root ! END IF IF ( my_rank == 0 ) THEN ! ! Write out computed state of board ! WRITE(name,"(A4,I4.4)") "Life",loop CALL INTDATA2MPGM(N,N,step(:,:,nx),name,4) END IF END DO ! processes should synchronize here ierr = 0 CALL Terminate(my_rank,ierr) END PROGRAM life subroutine IntData2Mpgm(s1,s2,idata,name,Mag) ! Simple subroutine to dump integer data in a PGM format implicit none INTEGER, INTENT(IN) :: s1, s2, Mag INTEGER, DIMENSION(s1,s2), intent(in) :: idata character(*), intent(in) :: name ! integer :: i, j, ouni, r, m integer :: vp, vs real :: rmin, rmax character(80) :: fname ! ! Write on unit 700 with PGM format ouni = 700 fname = TRIM(name)//".pgm" open(ouni,file=trim(fname),status="replace",iostat=vs) if ( vs /= 0 ) then WRITE(*,*) "!!!! Error write access to file ",trim(fname) end if ! Magic code write(ouni,"(a)") "P2" ! Dimensions write(ouni,*) s1*Mag, s2*Mag ! Maximum value write(ouni,"(a)") "255" ! Values from 0 to 255 rmin = MINVAL(idata); rmax = MAXVAL(idata) vs = 0 do i = 1, s1 DO r = 1, Mag do j = 1, s2 vp = INT ( (idata(i,j) - rmin) * 255.0 / (rmax - rmin) ) DO m = 1, Mag write(ouni,"(i4)",advance="no") vp vs = vs + 1 END DO if (vs >= 10 ) then write(ouni,"(a)") " " vs = 0 end if end do write(ouni,"(a)") " " vs = 0 END DO end do close(ouni) return end subroutine IntData2Mpgm SUBROUTINE ProcessBand(length,istart,iend,intervals,n) IMPLICIT NONE INTEGER, INTENT(IN) :: length,intervals,n INTEGER, INTENT(OUT) :: istart,iend ! INTEGER :: delta ! delta = ( length + (intervals - 1) ) / intervals istart = delta * n + 1; iend = delta * ( n + 1) if ( iend > length ) iend = length ! RETURN END SUBROUTINE ProcessBand SUBROUTINE Terminate(p,rc) IMPLICIT NONE ! INTEGER, INTENT(IN) :: P INTEGER, INTENT(IN OUT) :: rc INTEGER :: ierr WRITE(*,*) "Process ",p," terminates" STOP END SUBROUTINE Terminate