! parallelpascalstriangle.f90 ! © Copyright 2003-4 Dauger Research, Inc. ! Our lawyers made us say this: ! DISCLAIMER: We provide the following on an "AS IS" basis. Use it at your own risk. module pascallib ! MPI library include 'mpif.h' contains ! Routines performing elemental work. subroutine addright(inputArray, inputSize) implicit none integer, dimension(:) :: inputArray integer :: inputSize, i if (size(inputArray).gt.1) then do i = inputSize, 1, -1 inputArray(i+1)=inputArray(i+1)+inputArray(i) end do end if end subroutine subroutine addleft(inputArray, inputSize) implicit none integer, dimension(:) :: inputArray integer :: inputSize, i if ((size(inputArray).gt.1)) then do i=1, inputSize inputArray(i)=inputArray(i)+inputArray(i+1) end do end if end subroutine subroutine iterationloop(theArray, arraySize, lastIteration, verbose, idproc, nproc) implicit none integer, dimension(:) :: theArray integer :: arraySize, lastIteration, verbose, index, i integer :: idproc, nproc integer :: leftIDProc, rightIDProc integer :: request, ierr integer, dimension(MPI_STATUS_SIZE) :: status if (arraySize.gt.0) then leftIDProc=idproc-1; rightIDProc=idproc+1 ! get to know my (processor's) neighbors if (leftIDProc.lt.0) leftIDProc=nproc-1 if (rightIDProc.ge.nproc) rightIDProc=0 ! loop over indicies do index = 0, lastIteration-1 ! call the left or right routine for each index, reusing array if (iand(1,index)/=0) then call addleft(theArray, arraySize) call MPI_IRECV(theArray(arraySize), 1, MPI_INTEGER, rightIDProc, index, MPI_COMM_WORLD, request, ierr) call MPI_SEND(theArray(1), 1, MPI_INTEGER, leftIDProc, index, MPI_COMM_WORLD, ierr) call MPI_WAIT(request, status, ierr) else call addright(theArray, arraySize) call MPI_IRECV(theArray(1), 1, MPI_INTEGER, leftIDProc, index, MPI_COMM_WORLD, request, ierr) call MPI_SEND(theArray(arraySize), 1, MPI_INTEGER, rightIDProc, index, MPI_COMM_WORLD, ierr) call MPI_WAIT(request, status, ierr) end if if (verbose/=0) then do i=1,arraySize if (iand(1,verbose)/=0) then write(*, '(I6)', advance="no") theArray(i) else if (iand(1,theArray(i))/=0) then write(*, '(A)', advance="no") '*' else write(*, '(A)', advance="no") ' ' end if end if end do print *," " end if end do end if end subroutine subroutine computeloop(theArray, binomialExponent, idproc, nproc) implicit none integer, dimension(:) :: theArray integer :: binomialExponent ! local copies of the data to be output integer :: arraySize, i integer :: idproc, nproc, ierr ! allocate an array to hold all the results integer, dimension(((binomialExponent+nproc)/nproc)+1) :: myArray arraySize=((binomialExponent+nproc)/nproc)+1 if (arraySize.gt.1) then ! clear the array do i=1, arraySize myArray(i)=0 end do ! seed the array if (idproc.eq.((binomialExponent/2)/(arraySize-1))) then myArray((binomialExponent/2)-idproc*(arraySize-1)+1)=1 end if ! propagate call iterationloop(myArray, arraySize, binomialExponent, 2, idproc, nproc) ! proc 0's has a bigger array so we can gather all the data at the end ! gathers the data from the other arrays ... call MPI_GATHER(myArray, arraySize-1, MPI_INTEGER, theArray, arraySize-1, MPI_INTEGER, 0, MPI_COMM_WORLD, ierr) ! ... to proc 0 end if ! return the array end subroutine function ppinit(idproc, nproc) implicit none ! this subroutine initializes parallel processing integer :: idproc ! = processor id integer :: nproc ! = number of real or virtual processors obtained integer :: ierr, ppinit nproc=0 ! initialize the MPI execution environment call MPI_INIT(ierr) if (ierr.eq.0) then ! determine the rank of the calling process in the communicator call MPI_COMM_RANK(MPI_COMM_WORLD, idproc, ierr) ! determine the size of the group associated with a communicator call MPI_COMM_SIZE(MPI_COMM_WORLD, nproc, ierr) end if ppinit = ierr end function subroutine ppexit() implicit none ! this subroutine terminates parallel processing integer :: ierr ! terminate MPI execution environment call MPI_Finalize(ierr) end subroutine end module program pascal use pascallib implicit none ! BinomialExponent specifies how far to propagate integer, parameter :: BinomialExponent = 30 ! main copies of the sum and the array integer, dimension(BinomialExponent*2) :: theArray integer :: ios, idproc, nproc, ierr ! initialize parallel processing ierr = ppinit(idproc, nproc) if (ierr.ne.0) stop ! stop right there if there's a problem print *, "I'm processor #", idproc, " in a ", nproc, "-processor cluster." print *,"Beginning computation..." call computeloop(theArray, BinomialExponent, idproc, nproc) if (idproc.eq.0) then! only processor 0 ! save the array into a data file open(unit = 2, file = "output", status = "replace", iostat = ios, form = "unformatted") if (ios .eq. 0) then print *, "writing array...\n" write(unit = 2) theArray endfile 2 end if end if write( *, '(I16)', advance="no") theArray(1:BinomialExponent) print *, " " ! clean up after myself call ppexit() stop end program