/*
** Global sumation using a ring
** Not very efficient as far as parallelism is concerned,
** but it is simple and uses a constant amount of storage.
** Copyright Rolf Riesen 2008
**
*/
#include <stdio.h>
#include <mpi.h>


int gsum(int summand, int root, MPI_Comm comm);



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

int my_rank, nproc;
int my_value;
int result;
int root;
int count;
int calc;
int i;



    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 */
    my_value= my_rank;
    result= 0;
    root= 0;
    count= 1;

    result= gsum(my_value, root, MPI_COMM_WORLD);

    printf("Node %3d: My result is %d\n", my_rank, result);
    if (my_rank == root)   {
	for (i= 0; i < nproc; i++)   {
	    calc= calc + i;
	}
	printf("Expected result is %d.\n", calc);
    }

    MPI_Finalize();
    return 0;

}  /* end of main() */



int
gsum(int summand, int root, MPI_Comm comm)
{

int my_rank, nproc;
int left, right;
int count= 1;
int tag= 0;
MPI_Status status;
int result;


    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);

    if ((root < 0) || (root >= nproc))   {
	MPI_Abort(MPI_COMM_WORLD, -1);
    }

    if (nproc <= 1)   {
	return summand;
    }

    /* Wait for the value from node my_rank - 1 */
    left= my_rank - 1;
    if (my_rank == 0)   {
	right= 1;
	MPI_Send(&summand, count, MPI_INT, right, tag, MPI_COMM_WORLD);
    } else   {
	MPI_Recv(&result, count, MPI_INT, left, tag, MPI_COMM_WORLD, &status);

	result= result + summand;

	/* Send our result to my_rank + 1 or the root */
	right= my_rank + 1;
	if (right >= nproc)   {
	    right= root;
	}

	MPI_Send(&result, count, MPI_INT, right, tag, MPI_COMM_WORLD);
    }

    if (my_rank == root)   {
	/* Wait for the result */
	MPI_Recv(&result, count, MPI_INT, MPI_ANY_SOURCE, tag, MPI_COMM_WORLD, &status);
	return result;
    }

    return 0;

}  /* end of gsum() */
