/*
** Calculate global sum using recursive doubling (halving)
** Based on code provided by Lena Lopez
** Copyright Rolf Riesen 2008
**
*/
#include <stdio.h>
#include <mpi.h>


/* Global values */
int my_rank, nproc;

/* Local gunctions */
static int gsum(int summand, MPI_Comm comm);



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

int result;


    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);

    /* Each node contributes its own node number */
    result= gsum(my_rank, MPI_COMM_WORLD);

    if (my_rank == 0)   {
	printf("Node %3d: Global sum result is %d\n", my_rank, result);
    }

    MPI_Finalize();
    return 0;

}  /* end of main() */



static int
gsum(int summand, MPI_Comm comm)
{

int tag= 0;
int left, right, parent;
int sum;
MPI_Status status;


    /* Who are my children and parent? */
    left= (my_rank * 2) + 1;
    right= (my_rank * 2) + 2;
    parent= (my_rank - 1) / 2;

    sum= summand;

    /* If left child exists, wait for its contribution. */
    if (left < nproc)   {
	MPI_Recv(&summand, 1, MPI_INT, left, tag, comm, &status);
	sum= sum + summand;
	/* If right child exists, wait for its contribution. */
	if (right < nproc)   {
	    MPI_Recv(&summand, 1, MPI_INT, right, tag, comm, &status);
	    sum= sum + summand;
	}
    }

    /* If we are below the root, send result to parent. */
    if (my_rank != 0)   {
	MPI_Send(&sum, 1, MPI_INT, parent, tag, comm);
    }

    return sum;

}  /* end of gsum() */
