      PROGRAM ASSIGNMENT4
      INCLUDE 'mpif.h'
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
c For each body in the array x, this program calculates a correlation 
c coefficient between that body and the bodies in array y.  The program
c is designed to run with Procs MPI processes, which can be altered 
c in the parameter below.  The number of bodies in the x and y arrays
c can also be altered below.  However, if bodies is set larger than
c 10,000, the provided data file will be insufficient to provide data.
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
c Setting the number of bodies and the number of MPI processes. 
c Adjust bodies to the number of bodies in the x and y arrays.
c bodies cannot be set to more than 10,000(Will run out of data).
c Adjust procs to the number of processors being used.
      Integer   	bodies, procs, n
      Parameter         (bodies=10000)
      Parameter         (procs=6)
      Parameter         (n=bodies/procs+1)

c Declaring other variables.
      Integer           status(MPI_STATUS_SIZE),left,right
      Integer           i, j, k, rank, size, ierr, remain
      Integer           iread, xwork, ywork, request
      Real              xx,yy
      Real*8            correlation(n), x(n), y(n), y2(n)
      Real*8            result, sum


c Initializing MPI and obtaining the process no. and no. of processes.
      call MPI_INIT(ierr)
      call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
      call MPI_COMM_SIZE(MPI_COMM_WORLD, size, ierr)
      if (size .ne. procs) then
         if (rank .eq. 0) then
            print*,"The number of processors must match the"
            print*,"number of processors specified in the program."
            print*,"Aborting the program."
         endif
         call MPI_FINALIZE(ierr)
         stop
      endif
    
c Determining the remainder and assigning the remaining
c elements to a processor.
      xwork=bodies/size
      iread=xwork*rank
      remain=bodies-(xwork*size)
      do i=1,remain
         if (rank .eq. i-1) xwork=xwork+1
         if (rank .ge. i) iread=iread+1
      enddo
      ywork=xwork

c Initializing the x and y arrays
      do i=1,n
         x(i)=0.0
         y(i)=0.0
      enddo

c Initializing the correlation array
      do i=1,n
         correlation(i)=0.0
      enddo

c Determining the left and right neighbors
      left=mod(rank-1+procs,procs)
      right=mod(rank+1+procs,procs)

c Reading in the x and y arrays.
      open(unit=11,file='data',status='old',
     $     access='direct',recl=8)
      do i=1,xwork
         read(11, rec=i+iread) xx,yy
         x(i) = xx
         y(i) = yy
      enddo 

c Looping over the number of processors
      do k=1,size

c Sending the y array to the right neighbor.
         call MPI_Isend(y,n,MPI_DOUBLE_PRECISION,right,
     $                  1,MPI_COMM_WORLD,request,ierr)

c Calculating the correlation for the currently available ys
         do i=1,xwork
            temp=x(i)*x(i)
            do j=1,ywork
               correlation(i)=correlation(i)+temp+y(j)*y(j)
            enddo
         enddo

c Waiting for the send to complete before overwriting
         call MPI_RECV(y2,n,MPI_DOUBLE_PRECISION,left,
     $                1,MPI_COMM_WORLD,status,ierr)

c Determining if the y's have a remainder and setting the
c amount of work (ywork) appropriately.
         if (y2(n) .eq. 0.0) then
            ywork=n-1
         else 
            ywork=n
         endif

c Replacing my set of ys with the new set after my set
c has been received.
         call MPI_Wait(request, status, ierr)
         do i=1,n
            y(i)=y2(i)
         enddo
      enddo

c Summing my correlation array
      sum=0.0
      do i=1,xwork
         sum=sum+correlation(i)
      enddo

c Combining the sums of the correlation arrays from ea. proc.
      call MPI_Reduce(sum,result,1,MPI_DOUBLE_PRECISION,
     $               MPI_SUM,0,MPI_COMM_WORLD,ierr)

      call MPI_FINALIZE(ierr)

c Printing the final answer
      if (rank .eq. 0) then
         print*,"The correlation is",result
      endif
      end

