/* ---------------------------------------------------------------
 *  pi_send.c
 *  FILES: code11pi_send.c, code11dboard.c, makecode11
 *  DESCRIPTION:  MPI pi calculation example program.  C Version.
 *    This program calculates pi using a "dartboard" algorithm.  See
 *    Fox et al.(1988) Solving Problems on Concurrent Processors, vol.1
 *    page 207.  All processes contribute to the calculation, with the
 *    master averaging the values for pi.
 *
 *    SPMD version:  Conditional statements check if the process  
 *    is the master or a worker.  
 *
 *    This version uses low level sends and receives to collect results
 *
 *  AUTHOR: Roslyn Leibensperger
 *  REVISED: 09/15/93 for latest API changes. BMB
 *           01/10/94 changed API to MPL. SMJP
 *           05/18/94 replaced blocking with non-blocking send. RYL
 *  CONVERTED TO MPI: 11/12/94 by  Xainneng Shen
 * --------------------------------------------------------------- */

#include <stdlib.h>
#include <stdio.h>
#include "mpi.h"
double dboard (int darts);

#define DARTS 5000      /* number of throws at dartboard */
#define ROUNDS 10       /* number of times "darts" is iterated */
#define MASTER 0        /* task ID of master task */

MPI_Status  status;
MPI_Request request;
main(int argc, char **argv) 
{  
double homepi,          /* value of pi calculated by current task */
       pi,              /* average of pi after "darts" is thrown */
       avepi,           /* average pi value for all iterations */
       pirecv,          /* pi received from worker */
       pisum;           /* sum of workers pi values */
int mytid,              /* task ID - also used as seed number */
    nproc,              /* number of tasks */
    source,             /* source of incoming message */  
    mtype,              /* message type */
    msgid,              /* message identifier */
    nbytes,             /* size of message */
    rcode,              /* return code */
    i, n;

/* Obtain number of tasks and task ID */
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &mytid); 
MPI_Comm_size(MPI_COMM_WORLD, &nproc);
printf ("MPI task ID = %d\n", mytid);

/* Set seed for random number generator equal to task ID */
srandom (mytid);

avepi = 0;
for (i = 0; i < ROUNDS; i++) {
     /* All tasks calculate pi using dartboard algorithm */
     homepi = dboard(DARTS);

     /* Workers send homepi to master */
     /* - Message type will be set to the iteration count */
     /* - A non-blocking send is followed by mpi_wait */
     /*   this is safe programming practice */
     if (mytid != MASTER) {
          mtype = i;
           MPI_Isend(&homepi, 1, MPI_DOUBLE, MASTER, mtype, 
              MPI_COMM_WORLD, &request);
          MPI_Wait(&request, &status);
          }

     /* Master receives messages from all workers */
     /* - Message type will be set to the iteration count */
     /*   a message can be received from any task, as long as the */ 
     /*   message types match */
     /* - The return code will be checked, and a message displayed */
     /*   if a problem occurred */
     else {
          mtype = i;
          pisum = 0;
          for (n = 1; n < nproc; n++) {
               MPI_Recv(&pirecv, 1, MPI_DOUBLE, MPI_ANY_SOURCE, mtype,
                     MPI_COMM_WORLD, &status);
               /* keep running total of pi */
               pisum = pisum + pirecv;
               }
          /* Master calculates the average value of pi for this iteration */
          pi = (pisum + homepi)/nproc;
          /* Master calculates the average value of pi over all iterations */
          avepi = ((avepi * i) + pi)/(i + 1);  
          printf("   After %3d throws, average value of pi = %10.8f\n",
                 (DARTS * (i + 1)),avepi);
          }     
    }  
    MPI_Finalize();
}

