/*
 *
 * Copyright 1998-1999, University of Notre Dame.
 * Authors: Jeffrey M. Squyres, Kinis L. Meyer with M. D. McNally 
 *          and Andrew Lumsdaine
 *
 * This file is part of the Notre Dame LAM implementation of MPI.
 *
 * You should have received a copy of the License Agreement for the
 * Notre Dame LAM implementation of MPI along with the software; see
 * the file LICENSE.  If not, contact Office of Research, University
 * of Notre Dame, Notre Dame, IN 46556.
 *
 * Permission to modify the code and to distribute modified code is
 * granted, provided the text of this NOTICE is retained, a notice that
 * the code was modified is included with the above COPYRIGHT NOTICE and
 * with the COPYRIGHT NOTICE in the LICENSE file, and that the LICENSE
 * file is distributed with the modified code.
 *
 * LICENSOR MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.
 * By way of example, but not limitation, Licensor MAKES NO
 * REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
 * PARTICULAR PURPOSE OR THAT THE USE OF THE LICENSED SOFTWARE COMPONENTS
 * OR DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS, TRADEMARKS
 * OR OTHER RIGHTS.  
 *
 * Additional copyrights may follow.
 *
 *
 *	University of Notre Dame LAM
 *      $Id: slave.c,v 6.3 1999/07/09 04:38:27 jsquyres Exp $
 * 
 *	Function:	- slave program for mandelbrot demo
 *			- fault tolerant version
 *			- initially receives mandelbrot complex plane desc.
 *			- receives work orders from the master
 *			- sends color buffers to the master
 */

#include <stdlib.h>
#include <errno.h>

#include <mpi.h>
#include "mandel.h"

/*
 * local functions
 */
static char		xy2color();


int
main(argc, argv)

int			argc;
char			*argv[];

{
	int		ulx, uly;		/* upper-left point */
	int		lrx, lry;		/* lower-right point */
	char		*p;			/* temp pointer */
	char		*region;		/* color buffer */
	int		region_size;		/* color buffer size (bytes) */
	int		i, j;			/* loop counters */
	float		scale_x; 		/* used to convert from */
	float		scale_y;		/* pixels to colors */
	float		translate_x;		/* ... */
	float		translate_y;		/* ... */
	float		init[4];		/* scaling factors */
	int		work[4];		/* work requests */
	int		rank_master;		/* master's world rank */
	int		rank_myself;		/* my own world rank */
	int		size;			/* world size */
	MPI_Comm	comm;			/* communicator with master */
	MPI_Comm	comm_junk;		/* throw away communicator */
	MPI_Status	status;			/* returned from MPI */

	MPI_Init(&argc, &argv);

	MPI_Comm_size(MPI_COMM_WORLD, &size);
	MPI_Comm_rank(MPI_COMM_WORLD, &rank_myself);
/*
 * Receive scaling and translating factors for grid.
 */
	MPI_Recv((void *) init, 4, MPI_FLOAT, MPI_ANY_SOURCE,
			MPI_ANY_TAG, MPI_COMM_WORLD, &status);

	rank_master = status.MPI_SOURCE;
/*
 * Create individual slave communicators.
 */
	for (i = 0; i < size; ++i) {
		if (i == rank_master) continue;

		if (i == rank_myself) {
			MPI_Comm_split(MPI_COMM_WORLD, 0, 1, &comm);
		} else {
			MPI_Comm_split(MPI_COMM_WORLD, MPI_UNDEFINED, 1,
					&comm_junk);
		}
	}

	scale_x = init[0];
	scale_y = init[1];
	translate_x = init[2];
	translate_y = init[3];
/*
 * Loop on work requests.
 */
	for (;;) {
		MPI_Recv((void *) work, 4, MPI_INT, 0, MPI_ANY_TAG,
				comm, &status);
/*
 * If we get a DIE message, we are all done, so just exit.
 */
		if (status.MPI_TAG == DIETAG) {
			break;
		}
/*
 * If we get here, we've gotten a message requesting us to do
 * some more work.  Compute the given region, send the result back to 
 * the master process, and wait for a new request.
 */
		ulx = work[0];
		lrx = work[1];
		uly = work[2];
		lry = work[3];

		region_size = (lrx - ulx + 1) * (lry - uly + 1);
		region = malloc((unsigned) region_size);
		if (region == 0) MPI_Abort(MPI_COMM_SELF, errno);

		p = region;

		for(j = uly; j <= lry; j++) {

			for(i = ulx; i <= lrx; i++) {
				*p++ = xy2color(translate_x + scale_x * i,
						translate_y + scale_y * j);
			}
		}
/*
 * Send back the computed colours.
 */
		MPI_Send(region, region_size, MPI_CHAR, 0, 0, comm);

		free(region);
	}

	MPI_Finalize();
	return(0);
}

/*
 *	xy2color
 * 
 *	Function:	- Given a point on the complex plane x+iy, 
 *			  return color based on how close the
 *			  point is to the Mandelbrot set.
 *	Accepts:	- point in complex plane
 *	Returns:	- 1 byte color
 */
static char
xy2color(x, y)

float			x, y;

{
	char		colour;
	int		i;
	complex		z, c;
	float		mag2;
	float		scale;

	scale = ((float) 255) / MAX_ITERATIONS;
	colour = -1;

	z.r = z.i = 0;
	c.r = x;
	c.i = y;

	for (i = 0; i < MAX_ITERATIONS; ++i) {

		x = (z.r * z.r) - (z.i * z.i) + c.r;
		y = (2 * z.r * z.i) + c.i;

		z.r = x;
		z.i = y;

		mag2 = (z.r * z.r) + (z.i * z.i);

		if (mag2 >= 4) {
			colour = (char) ((i * scale) + 0.5);
			break;
		}
	}

	return(colour);
}
