/*
** $Id: mandel.c,v 1.1 2008/02/28 22:56:51 rolf Exp $
** Rolf Riesen, April 2007
**
** A parallel code to compute Mandelbrot sets
*/
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <string.h>
#include <errno.h>
#include <math.h>
#include <mpi.h>



/* Some constants */
#define TRUE		(1)
#define FALSE		(0)
#define THRESHHOLD	(2.0)
#define MAX_RGB_VALUE	(255)



/* Define a cell */
typedef struct cell_t   {
    int cnt;		/* At which count did this cell go beyond 2.0? */
    double value;	/* Value after iter iterations */
    int in_set;		/* Is this pixel in the set? */
    int pixel_r;	/* Red value of pixel */
    int pixel_g;	/* Green value of pixel */
    int pixel_b;	/* Blue value of pixel */
} cell_t;



/* Some globals to keep things simple */
int my_rank, nnodes;



/* Local functions */
void usage(char *pname);



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

int ch, rc;
int debug;
char *fname;
FILE *fp;
int black;
int optcount;
double LleftR, LleftI, UrightR, UrightI;
int iter, xres, yres;


    /* Initialize MPI */
    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
    MPI_Comm_size(MPI_COMM_WORLD, &nnodes);


    /* Some defaults */
    debug= 0;
    rc= 0;
    fname= NULL;
    fp= NULL;
    black= FALSE;
    optcount= 0;

    while ((ch= getopt(argc, argv, "vbf:")) != EOF)   {
        switch (ch)   {
            case 'v': debug++;
		      optcount++;
                      break;
            case 'b': black= TRUE;
		      optcount++;
                      break;
	    case 'f': fname= optarg;
		      optcount++;
		      break;
            default:  if (my_rank == 0)   {
			  usage(argv[0]);
		      }
		      MPI_Finalize();
		      exit(-1);
        }
    }

    if ((argc - optcount) < 7)   {
	if (my_rank == 0)   {
	    fprintf(stderr, "Error: Need more arguments\n");
	    usage(argv[0]);
	}
	rc= -1;
    }

    if ((my_rank == 0) && (rc == 0))   {
	if (fname != NULL)   {
	    fp= fopen(fname, "w");
	    if (fp == NULL)   {
		fprintf(stderr, "Error: Cannot open file \"%s\": %s\n", fname, strerror(errno));
		rc= -1;
	    }
	} else   {
	    fp= stdout;
	}
    }

    if (rc == 0)   {
	errno= 0;
	LleftR = strtod(argv[optind++], NULL);
	if (errno)   {
	    if (my_rank == 0)   {
		fprintf(stderr, "Error: Reading real part of lower left: \"%s\": %s\n", argv[optind], strerror(errno));
	    }
	    rc= -1;
	}
    }
    if (rc == 0)   {
	errno= 0;
	LleftI = strtod(argv[optind++], NULL);
	if (errno)   {
	    if (my_rank == 0)   {
		fprintf(stderr, "Error: Reading imaginary part of lower left: \"%s\": %s\n", argv[optind], strerror(errno));
	    }
	    rc= -1;
	}
    }
    if (rc == 0)   {
	errno= 0;
	UrightR = strtod(argv[optind++], NULL);
	if (errno)   {
	    if (my_rank == 0)   {
		fprintf(stderr, "Error: Reading real part of upper right: \"%s\": %s\n", argv[optind], strerror(errno));
	    }
	    rc= -1;
	}
    }
    if (rc == 0)   {
	errno= 0;
	UrightI = strtod(argv[optind++], NULL);
	if (errno)   {
	    if (my_rank == 0)   {
		fprintf(stderr, "Error: Reading imaginary part of upper right: \"%s\": %s\n", argv[optind], strerror(errno));
	    }
	    rc= -1;
	}
    }
    if (rc == 0)   {
	errno= 0;
	iter = strtol(argv[optind++], NULL, 10);
	if (errno)   {
	    if (my_rank == 0)   {
		fprintf(stderr, "Error: Reading number of iterations: \"%s\": %s\n", argv[optind], strerror(errno));
	    }
	    rc= -1;
	}
	errno= 0;
    }
    if (rc == 0)   {
	xres = strtol(argv[optind++], NULL, 10);
	if (errno)   {
	    if (my_rank == 0)   {
		fprintf(stderr, "Error: Reading X-resolution: \"%s\": %s\n", argv[optind], strerror(errno));
	    }
	    rc= -1;
	}
    }
    if (rc == 0)   {
	errno= 0;
	yres = strtol(argv[optind++], NULL, 10);
	if (errno)   {
	    if (my_rank == 0)   {
		fprintf(stderr, "Error: Reading Y-resolution: \"%s\": %s\n", argv[optind], strerror(errno));
	    }
	    rc= -1;
	}
    }

    if (rc != 0)   {
	MPI_Abort(MPI_COMM_WORLD, -1);
    }

    if (debug)   {
	if (my_rank == 0)   {
	    fprintf(stderr, "Computing Mandelbrot set for coordinates: %g,%g %g,%g\n", LleftR, LleftI, UrightR, UrightI);
	    fprintf(stderr, "Number of iterations: %d\n", iter);
	    if (black)   {
		fprintf(stderr, "Picture size (in black and white): %dx%d\n", xres, yres);
	    } else   {
		fprintf(stderr, "Picture size (in color): %dx%d\n", xres, yres);
	    }
	}
    }

    /*
    ** This is where you call your code to do the calculation
    */

    MPI_Finalize();

    return 0;

}  /* end of main() */



void
usage(char *pname)
{

    if (my_rank == 0)   {
	fprintf(stderr, "Usage: %s [-v] [-b] [-f outfile] LleftR LlfetI UrightR UrightL Iter Xres Yres\n", pname);
	fprintf(stderr, "            outfile   File to store picture (default: stdout)\n");
	fprintf(stderr, "            -b        Produce a black and white version of the picture\n");
	fprintf(stderr, "            -v        Be verbose for debugging\n");
	fprintf(stderr, "            LleftR    Real part of lower left pixel\n");
	fprintf(stderr, "            LleftI    imaginary part of lower left pixel\n");
	fprintf(stderr, "            UrightR   Real part of upper right pixel\n");
	fprintf(stderr, "            UrightI   imaginary part of upper right pixel\n");
	fprintf(stderr, "            Iter      Number of iterations per pixel\n");
	fprintf(stderr, "            Xres      X-axis resolution in pixels\n");
	fprintf(stderr, "            Yres      Y-axis resolution in pixels\n");
    }

}  /* end of usage() */
