C  ------------------------------------------------------------------------
C   pi_reduce.f
C   FILES: pi_reduce.f, dboard.f, make.pi.f
C   DESCRIPTION:  MPI pi calculation example program.  Fortran version.
C     This program calculates pi using a "dartboard" algorithm.  See
C     Fox et al.(1988) Solving Problems on Concurrent Processors, vol.1
C     page 207.  All processes contribute to the calculation, with the
C     master averaging the values for pi.  
C      
C     SPMD Version:  Conditional statements check if the process is the
C     master or a worker.
C
C     This version uses mpi_reduce to collect results
C  
C   AUTHOR: Roslyn Leibensperger (C program for PVM).
C   REVISED: 05/11/93 Blaise Barney    Ported to Fortran.
C            06/01/93 R. Leibensperger Ported to API.
C            01/10/94 S. Pendell       Changed API to MPL.
C            05/18/94 R. Leibensperger Correction to comments.
C   CONVERTED TO MPI: 11/12/94 by Xianneng Shen.
C  ------------------------------------------------------------------------
C Explanation of constants and variables used in this program:
C   DARTS               = number of throws at dartboard  
C   ROUNDS              = number of times "DARTS" is iterated  
C   MASTER              = task ID of master task
C   mytid               = task ID of current task  
C   nproc               = number of tasks
C   homepi              = value of pi calculated by current task
C   pisum               = sum of tasks' pi values  
C   pi                  = average of pi for this iteration
C   avepi               = average pi value for all iterations  
C   seednum             = seed number - based on mytid
C   sbytes              = size of message being sent
C  ------------------------------------------------------------------------

      program pi_reduce
      include 'mpif.h'
      integer DARTS, ROUNDS, MASTER
      parameter(DARTS = 5000)  
      parameter(ROUNDS = 10)
      parameter(MASTER = 0)
      integer ierr
      integer   mytid, nproc, sbytes,  i
      real*4    seednum
      real*8    homepi, pi, avepi, pisum, dboard

C     Obtain number of tasks and task ID
      call mpi_init(ierr)
      call mpi_comm_rank(MPI_COMM_WORLD, mytid, ierr)
      call mpi_comm_size(MPI_COMM_WORLD, nproc, ierr)
      write(*,*)'MPI task id = ', mytid


C     Use the task id to set the seed number for the random number generator.
      seednum = real(mytid)
      call srand(seednum)

      avepi = 0

      do 40 i = 1, ROUNDS
C     Calculate pi using dartboard algorithm  
      homepi = dboard(DARTS)

C     Use mpi_reduce to sum values of homepi across all tasks
C     Master will store the accumulated value in pisum
C     - homepi is the send buffer
C     - pisum is the receive buffer (used by the receiving task only)
C     - sbytes is the size of the message
C     - MASTER is the task that will receive the result of the reduction
C       operation
      sbytes = 8
      call mpi_reduce(homepi, pisum, 1, MPI_DOUBLE_PRECISION,
     .      MPI_SUM, MASTER, MPI_COMM_WORLD, ierr)

C     Master computes average for this iteration and all iterations  
      if (mytid .eq. MASTER) then
        pi = pisum/nproc
        avepi = ((avepi*(i-1)) + pi) / i
        write(*,32) DARTS*i, avepi
 32     format('   After',i6,' throws, average value of pi = ',f10.8)  
      endif

 40   continue
      call mpi_finalize(ierr)
      end