/* 
 * example for dynamic task creation
 */

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <mpi.h>

#define WORKER           "slave"
#define TAG_WORK         1
#define TAG_RESULT       2
#define DEFAULT_ANZAHL   10000L       /* Defaultwert für Anzahl */


void main(int argc, char *argv[]) {

  int         nTasks;                   /* number of tasks */
  int         maxproc, nslaves;         /* number of tasks: max, slaves */
  int         *maxproc_p, flag;
  long        total;                    /* total number of points */
  long        mytotal;                  /* number of points per process */
  long        myhits;                   /* number of hits per process */
  long        totalhits;                /* total number of hits */
  double      pi;                       /* result */
  MPI_Comm    slavecomm;                /* intercomm */

  /* Anzahl der zu wuerfelnden Punkte pro Prozessor */
  if (argc != 2) {
    total = DEFAULT_ANZAHL;
  } else {
    total = 1000 * atol(argv[1]);
  }

  MPI_Init(&argc, &argv);
  MPI_Comm_size(MPI_COMM_WORLD, &nTasks);

  if (nTasks != 1) {
    printf("Warning: program should be started with just one task!\n");
  }

  /* get maximal number of tasks */
  MPI_Attr_get(MPI_COMM_WORLD, MPI_UNIVERSE_SIZE, &maxproc_p, &flag);
  if (flag) {
    maxproc = *maxproc_p;
  } else {
    printf("MPI_UNIVERSE_SIZE not set! Proceed fingers crossed\n");
    maxproc = 4;
  }
  printf("MPI_UNIVERSE_SIZE = %d\n", maxproc);    
  
  /* compute number of slaves */
  if (maxproc > 1) {
    nslaves = maxproc - 1;
  } else {
    nslaves = 2;
    printf("maxproc to small, trying to get 2 slaves!\n");
  }

  MPI_Spawn(WORKER, MPI_ARGV_NULL, nslaves, MPI_INFO_NULL, 0, 
	    MPI_COMM_WORLD, &slavecomm, MPI_ERRCODES_IGNORE);

  /* compute partial work for first part and send it to slaves */
  mytotal = (long) ceil(total/nslaves);
  total = nslaves * mytotal;              /* correct total */

  MPI_Bcast(&mytotal, 1, MPI_LONG, MPI_ROOT, slavecomm);

  /* combine partial results */
  totalhits = 0;
  MPI_Reduce(&myhits, &totalhits, 1, MPI_LONG, MPI_SUM, MPI_ROOT, slavecomm);
  
  /* compute final result */
  pi = totalhits/(double)total*4;
  printf("using %2d tasks: PI = %lf\n", nslaves, pi);
  
  MPI_Finalize();
}