/* sr_master.c: administrator for Simpson's 1/3 Rule of Integration;
   sr_master divides up the interval and sends out the interval number
   to sr_slave, who calculates that interval's contribution to the
   total area and returns it to sr_master. for this particular example,
   we are integrating the function f(x) = cos(50x)*exp(-3x) + 1 on the
   interval [0,1] */

#include "mypvm.h"

long errt;
struct timeval tp;
int numt[], tid[];

main()
{

int i, j, info, count, NUM;
int recv, buferr, bytes, msgtag, ttid, start, dstart, end, dend;
double area, back, h, f1, fnm1, fn, sum, tot;


/* define number of processors */
NUM = 3;

/* start timer */
errt = gettimeofday(&tp, NULL);
start = tp.tv_sec;
dstart = tp.tv_usec;

/* spawn process on each processor */
for (i = 0; i < NUM; i++) 
  numt[i] = pvm_spawn("sr_slave", (char**)0, 0, "", 1, &tid[i]);


/* define integration parameters */
h = (b - a)/ (double) STEPS;
area = 0.0;


/* since end terms are not symmetric with middle terms (computed by
   workers), compute them separately and add in afterwards */
f1 = cos(50.0*a) * exp(-3.0*a) + 1.0;
fnm1 = cos(50.0*(b-h)) * exp(-3.0*(b-h)) + 1.0;
fn = cos(50.0*b) * exp(-3.0*b) + 1.0;


/* ********* BEGIN SENDING ********* */
for (i = 0; i < NUM; i++) {
  ttid = tid[i];

  /* send out count=current step # */
  pvm_initsend(PvmDataDefault);
  pvm_pkint(&i, 1, 1);
  pvm_pkint(&NUM, 1, 1);
  info = pvm_send(ttid, i);
  if (info < 0) {
    printf("error sending!\n");
    exit(1);
  }
}
/* ********** END SENDING ********** */


count = 0;
sum = 0;

/* ******** BEGIN RECEIVING ********* */
for (;;) {
  
  /* if all tasks done, kill processors and exit */
  if (count == NUM) {
    for (j = 0; j < NUM; j++)
      pvm_kill(tid[j]);
    pvm_exit();
    area = (h/3.0)*(f1 + sum + 4.0*fnm1 + fn); 
    errt = gettimeofday(&tp, NULL);
    end = tp.tv_sec;
    dend = tp.tv_usec;
    tot = (double) (end-start) + 10e-7 * (double) dend - 10e-7 * (double) dstart;
    printf("Simpson's 1/3 Rule:Area=%1.14f   err from exact ans=%1.14f\n", area, area - EXACT);  
    printf("time elapsed=%f sec   #workers=%d   #steps=%d\n",tot, NUM, STEPS);
    exit(0);
  } 


  /* receive from anyone who's sending */
  recv = pvm_recv(-1, -1);
  buferr = pvm_bufinfo(recv, &bytes, &msgtag, &ttid);

  /* read in step contribution */
  pvm_upkdouble(&back, 1, 1);

  pvm_freebuf(recv);

  /* add area contribution */
  sum += back;
  count += 1;

} /* end infinite for */
/* ******** END RECEIVING ********* */
    
} /* end sr_master.c */




