/* 
   Standard Deviaton Program
   Parallel Computing
   Jim Garlick
   2/16/1999
*/

#include <stdio.h>
#include <math.h>
#include "pvm3.h"
#include "stddev.h"
  
int main (int argc, char* argv[]) {
  
  /* File and data info */
  char filename[256];
  FILE *input;
  /* Pointer that will contain the entire data set array */
  float *data;
  int count, i, n;
  float tmp_sum, sum=0.0, mean, variance, stddev;
  char tmp[32];
  
  /* Process information */
  int my_tid, tids[32];
  int nhost, narch, num_spawned;
  struct pvmhostinfo *hostp;
  
  /* Get info from command line */
  if (argc != 2) {
    printf("Filename not specified.\n");
    exit(1);
  }
  strcpy(filename, argv[1]);
  
  /* Open the file for reading */
  if ((input = fopen(filename, "r")) == NULL) {
    fprintf(stderr, "Error opening %s\n", filename);
    exit(1);
  }
   
    /* Count the number of numbers in the file (pretty hokie) */
  for(n=0; fgets(tmp, sizeof(tmp), input); n++);
  rewind(input);
  printf("There are %d numbers.\n", n);

    /* Allocate the array */
  data = (float*)malloc(n * sizeof(float));

    /* Read in the numbers */
  for(i=0; fgets(tmp, sizeof(tmp), input); i++)
    sscanf(tmp, "%f", &data[i]);

 /* Start PVM stuff */
    /* Get my task id */ 
  my_tid = pvm_mytid();

  /* If we were given a number after the filename, */
/*  if (argc == 3)
    nhost = atoi(argv[2]);*/
  /* spawn that many processes */
    /* Get virtual machine configuration */
  pvm_config(&nhost, &narch, &hostp);

    /* Start up child processes */;
  num_spawned = pvm_spawn(SLAVE, 0, PvmTaskDefault, "", nhost, tids);
  if (num_spawned < 1) {
    fprintf(stderr, "Sorry, not enough hosts.\n");
    exit(1);
  }
  printf("%d spawned.\n", num_spawned);

  count = (n/num_spawned);
    /* Send the numbers to the children */
  for (i=0; i<num_spawned; i++) {
      /* initialize the buffers */
    pvm_initsend(PvmDataDefault);
      /* pack count */
    pvm_pkint(&count, 1, 1);
      /* pack the array */
    pvm_pkfloat(&data[(n/num_spawned)*i], count, 1);
      /* Send off the info */
    pvm_send(tids[i], SendData);
  }

    /* Polish off the rest of the numbers */
      /* This also keeps the master busy for a sec... */
  for(sum=0.0, i=(n/num_spawned)*i; i<n;  i++)
    sum += data[i];

    /* intercept the sums */
  for(i=0; i<num_spawned; i++) {
    pvm_recv(-1, SendSum);
    pvm_upkfloat(&tmp_sum, 1, 1);
    sum += tmp_sum;
  }
  
    /* Calculate the mean! */
  mean = sum/n;
  printf("Mean: %f\n", mean);

  /* Broadcast the mean back to everybody so they could 
     calculate the partial variance */
    /* Initialize the buffer */
  pvm_initsend(PvmDataDefault);
    /* Pack the mean up */
  pvm_pkfloat(&mean, 1, 1);
    /* multicast it to all of the processes */
  pvm_mcast(tids, num_spawned, SendMean);

    /* Again...polish off the remaining numbers */
  for(sum=0.0, i=num_spawned* (int) (n/num_spawned); i<n; i++)
    sum += pow((data[i]-mean), 2);

    /* Add up the returning totals */
  for(i=0; i<num_spawned; i++) {
    pvm_recv(-1, SendSum);
    pvm_upkfloat(&tmp_sum, 1, 1);
    sum += tmp_sum;
  }
 
  /* Now we know everything we need to know to calculate the variance
     and the standard deviation */
  variance = sum/n;
  printf("Variance: %f\n", variance);
  stddev = sqrt(variance);
  printf("Standard Deviation: %f\n", stddev);
}
