void main(int argc, int *argv[]) { //Here we create a 1 dimensional array that will be the total size of the image (in pixels). Because //this array can get so big, we need to declare it on the heap and NOT the stack (i.e. how one would normally //declare an array. So we use malloc(); int *MSet = (int*)malloc(nx*ny*sizeof(int)); int maxiter= 2000; //max number of iterations //Here, you can change the minimum and maximum values for the "window" that the image sees. increase the values (in sync) //and you will zoom out. Decrease them, and you will effectively zoom into the image. int xmin=-3, xmax= 1; int ymin=-2, ymax= 2; double threshold = 1.0; double dist = 0.0; int ix, iy; double cx, cy; int iter, i = 0; double x,y,x2,y2 = 0.0; double temp=0.0; double xder=0.0; double yder=0.0; double xorbit[maxiter+1]; xorbit[0] = 0.0; double yorbit[maxiter+1]; yorbit[0] = 0.0; double huge = 100000; bool flag = false; const double overflow = DBL_MAX; double delta = (threshold*(xmax-xmin))/(double)(nx-1); //We use a nested loop here to effectively traverse over each part of the grid (pixel of the image) in sequence. First, the complex values of the points are //determined and then used as the basis of the computaion. Effectively, it will loop over each point (pixel) and according on how many iterations it takes for //the value that the mathematical function returns on each iteration it will determine whether or not the point "escapes" to infinity (or an arbitrarily large //number.) or not. If it takes few iterations to escape then it will decide that this point is NOT part of the Mandelbrot set and will put a 0 in that point's //index in MSet. If it takes nearly all or all of the iterations to escape, then it will decide that the point/pixel is part of the Mandelbrot set and instead //put a 1 in its place in MSet. for (iy=0; iy<=(ny-1); iy++) { cy = ymin+iy*(ymax-ymin)/(double)(ny-1); for (ix = 0; ix<=(nx-1); ix++) { iter = 0; i = 0; x = 0.0; y = 0.0; x2 = 0.0; y2 = 0.0; temp = 0.0; xder = 0.0; yder = 0.0; dist = 0.0; cx = xmin +ix*(xmax-xmin)/(double)(ny-1); //This is the main loop that determins whether or not the point escapes or not. It breaks out of the loop when it escapes for (iter =0; iter<=maxiter; iter++) { temp = x2-y2 +cx; y = 2.0*x*y+cy; x = temp; x2 = x*x; y2 = y*y; xorbit[iter+1]=x; yorbit[iter+1]=y; if (x2+y2>huge) break; //if point escapes then break to next loop } //if the point escapes, find the distance from the set, just incase its close to the set. if it is, it will make it part of the set. if (x2+y2>=huge) { xder, yder = 0; i = 0; flag = false; for (i=0;i<=iter && flag==false;i++) { temp = 2.0*(xorbit[i]*xder-yorbit[i]*yder)+1; yder = 2.0*(yorbit[i]*xder+xorbit[i]*yder); xder = temp; flag = fmax(fabs(xder), fabs(yder)) > overflow; } if (flag == false) { dist=(log(x2+y2)*sqrt(x2+y2))/sqrt(xder*xder+yder*yder); } } //Assign the appropriate values to MSet in the place relating to the point in question if (dist < delta) MSet[iy * ny + ix] = 1; else MSet[iy * ny + ix] = 0; } } //Finally write the image. This funcion is defined in tiff.c. Refer to that file for more indepth usage of libTiff in C. calc_pixel_value(nx,ny,MSet,maxiter); }
int main(int argc, char *argv[]) { //First of all, initialize the MPI region. You can only call MPI functions (send, recv, gather, scatter, etc) //from inside this region (between MPI_Init() and MPI_Finalize()) MPI_Init(&argc, &argv); //Here we create a 1 dimensional array that will be the total size of the image (in pixels). Because //this array can get so big, we need to declare it on the heap and NOT the stack (i.e. how one would normally //declare an array. So we use malloc(); int *MSet = (int*)malloc(nx*ny*sizeof(int)); memset(MSet, 0, nx*ny*sizeof(int)); //Get rank number and total number of processes that were launched MPI_Comm_size(MPI_COMM_WORLD, &commSize); MPI_Comm_rank(MPI_COMM_WORLD, &myRank); //Check to see if the resolution and number of processes are compatable. if (myRank == 0) { if ((nx*ny)%(commSize-1) != 0) { printf("Incompatable number of processes requested\nExiting...\n"); exit(EXIT_FAILURE); } } int totalRes = (nx*ny); int chunkSize = totalRes/(commSize-1); if (myRank == 0) printf("Starting Calculation of Mandelbrot set...\n"); int i; MPI_Barrier(MPI_COMM_WORLD); //This only happens on the manager rank (rank 0). Basically it will compute the boundaries of the section of MSet each of the other //compute nodes will process and the size of the region and send them to the appropriate process. Then it will wait (block) until it recieves //the completed section of the array it was assigned. When its recieved it will copy it into the right place in MSet if (myRank == 0) { int myStart = 0, myEnd = 0; int* tempMSet = (int*)malloc((chunkSize)*sizeof(int)); for (i = 1; i<commSize; i++) { myStart = (chunkSize/ny)*(i-1); myEnd = (myStart + (chunkSize/ny)); //send to each node //tag 0 = startIdx //tag 1 = endIdx //tag 2 = chunkSize MPI_Send(&myStart, 1, MPI_INT, i, 0, MPI_COMM_WORLD); MPI_Send(&myEnd, 1, MPI_INT, i, 1, MPI_COMM_WORLD); MPI_Send(&chunkSize, 1, MPI_INT, i, 2, MPI_COMM_WORLD); printf("Sent chunk data to node %d\n", i); } int sender = -1; MPI_Status status; //Recieve the completed chunks and memcpy it onto MSet for (i = 1; i<commSize; i++) { MPI_Recv(tempMSet, chunkSize, MPI_INT, MPI_ANY_SOURCE, 3, MPI_COMM_WORLD, &status); sender = status.MPI_SOURCE; printf("Recieved chunk from %d\n",sender); memcpy(MSet+(chunkSize*(sender-1)), tempMSet, chunkSize*sizeof(int)); printf("Memcpy'd data from rank %d into MSet\n", sender); sender = -1; } } //This block is only exectued on the rest of the processes. First, it will recive the data from rank 0 then Do the same calculation on the smaller //set of points then send the completed region back to the manager rank. else if (myRank != 0) { int myStart = 0; int myEnd = 0; int chunkSize = 0; MPI_Status status; MPI_Recv(&myStart, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status); MPI_Recv(&myEnd, 1, MPI_INT, 0, 1, MPI_COMM_WORLD, &status); MPI_Recv(&chunkSize, 1, MPI_INT, 0, 2, MPI_COMM_WORLD, &status); //DO THE MANDEL calcSet(myStart, myEnd, chunkSize); } MPI_Barrier(MPI_COMM_WORLD); //Once the final array (MSet) is completed, it will call the same tiff writing funcion from tiff.c and write the image out as output.tif if (myRank == 0) { printf("Starting to write image\n"); calc_pixel_value(nx,ny,MSet,maxiter); } //End the MPI instance MPI_Finalize(); }