/*
 * Copyright (c) 2001-2003 The Trustees of Indiana University.  
 *                         All rights reserved.
 * Copyright (c) 1998-2001 University of Notre Dame. 
 *                         All rights reserved.
 * Copyright (c) 1994-1998 The Ohio State University.  
 *                         All rights reserved.
 * 
 * This file is part of the LAM/MPI software package.  For license
 * information, see the LICENSE file in the top level directory of the
 * LAM/MPI source distribution.
 * 
 * $HEADER$
 *
 * $Id: slave.c,v 6.8 2003/04/23 22:32:12 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 <stdio.h>
#include <errno.h>

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

/*
 * local functions
 */
static char xy2color(float x, float y);


int
main(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 size;			/* world size */
  MPI_Comm comm;		/* communicator with master */
  MPI_Status status;		/* returned from MPI */

  MPI_Init(&argc, &argv);

  MPI_Comm_size(MPI_COMM_WORLD, &size);
  MPI_Comm_get_parent(&comm);
  if (comm == MPI_COMM_NULL) {
    printf("No parent!");
    MPI_Abort(MPI_COMM_WORLD, (1 << 16) + 1);
  }

  /* Receive scaling and translating factors for grid. */

  MPI_Recv((void *) init, 4, MPI_FLOAT, 0, WORKTAG, comm, MPI_STATUS_IGNORE);

  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, REPLYTAG, 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(float x, float 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);
}


syntax highlighted by Code2HTML, v. 0.9.1