Generate mandelbrot images using many clustered computers

slave.c 5.1KB

    #include<stdio.h> #include<stdlib.h> #include<mpi.h> #include<math.h> #include<gmp.h> #include "types.h" void map(mpf_t out, double x, double in_min, double in_max, mpf_t out_min, mpf_t out_max, int precision) { mpf_t a, b, c; mpf_init2(a, precision); mpf_init2(b, precision); mpf_init2(c, precision); mpf_set_d(a, x); mpf_set_d(b, in_min); mpf_set_d(c, in_max); mpf_sub(a, a, b); mpf_sub(c, c, b); mpf_sub(b, out_max, out_min); mpf_mul(a, a, b); mpf_div(a, a, c); mpf_add(out, a, out_min); mpf_clear(a); mpf_clear(b); mpf_clear(c); //return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } Pixel hsl_to_rgb(double h, double s, double l) { while(h >= 360) h -= 360; if(s > 1) s = 1; if(l > 1) l = 1; double c = (1 - abs(2 * l - 1)) * s; double x = c * (1 - fabs(fmod(((double)h)/60, 2) - 1)); double m = l - c / 2; double r, g, b; int q = h / 60; switch(q) { case(0): r = c; g = x; b = 0; break; case(1): r = x; g = c; b = 0; break; case(2): r = 0; g = c; b = x; break; case(3): r = 0; g = x; b = c; break; case(4): r = x; g = 0; b = c; break; case(5): r = c; g = 0; b = x; } Pixel out; out.red = 255 * (r + m); out.green = 255 * (g + m); out.blue = 255 * (b + m); return out; } Pixel mandelbrot(int pixId, int w, int h, mpf_t xMin, mpf_t xMax, mpf_t yMin, mpf_t yMax, long range, long maxIter, int precision) { int x = pixId % w; int y = pixId / w; //double bounds[] = {center[0] - range, center[1] - range, // center[0] + range, center[1] + range}; mpf_t Creal; mpf_init2(Creal, precision); map(Creal, x, 0, w, xMin, xMax, precision); //printf("%lf %lf %lf\r\n",mpf_get_d(rangeG), mpf_get_d(xMin), mpf_get_d(xMax)); //double Creal = map(x, 0, w, bounds[0], bounds[2]); mpf_t Ci; mpf_init2(Ci, precision); map(Ci, y, 0, h, yMin, yMax, precision); //double Cimaginary = map(y, 0, h, bounds[1], bounds[3]); Pixel rtn; mpf_t real, imag, tmp, imagS; mpf_init2(real, precision); mpf_init2(imag, precision); mpf_init2(tmp, precision); mpf_init2(imagS, precision); mpf_set_d(real, 0); mpf_set_d(imag, 0); int i = 0; for(; i < maxIter; i++) { mpf_set(tmp, real); //real = real*real - imaginary*imaginary + Creal; mpf_mul(real, real, real); //real = real^2 mpf_mul(imagS, imag, imag); mpf_sub(real, real, imagS); mpf_add(real, real, Creal); //imaginary = realTmp * 2 * imaginary + Cimaginary; mpf_mul_ui(imag, imag, 2); mpf_mul(imag, imag, tmp); mpf_add(imag, imag, Ci); //if(imaginary * imaginary + real * real > 4 || // imaginary * imaginary + real * real < -4) mpf_mul(imagS, imag, imag); mpf_mul(tmp, real, real); mpf_add(tmp, imagS, tmp); if(mpf_cmp_si(tmp, 1<<16) > 0) { //We can use regular doubles here double log_zn = log2(mpf_get_d(tmp)) / 2; double nu = log2(log_zn); //this can be optimized double il = i + 1 - nu; rtn = hsl_to_rgb(il * 10, 1, 0.5); break; } } if(i == maxIter) rtn = (Pixel){.red=0, .green=0, .blue=0}; mpf_clears(real, imag, tmp, imagS, Ci, Creal, NULL); return rtn; } void getConfig(Config *conf) { MPI_Recv(conf, sizeof(Config), MPI_BYTE, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); } void slave_main(int slaveCount, int id) { Config conf; Pixel *buf = NULL; while(1) { long curPixel; MPI_Recv(&curPixel, 1, MPI_LONG, 0, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); if(curPixel == -1) break; if(curPixel == -2) { getConfig(&conf); if(buf == NULL) { buf = malloc(sizeof(Pixel) * conf.batch); } } else { int amtToSend = MIN(conf.batch, ((long)conf.w * conf.h) - curPixel); MPI_Recv(buf, sizeof(Pixel) * amtToSend, MPI_BYTE, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); //Processing int precision = 4 * abs(conf.zoomExp) * MAX(10, log(conf.zoomBase)); //printf("Precision: %d\r\n", precision); mpf_t cX; mpf_t cY; mpf_init2(cX, precision); mpf_init2(cY, precision); mpf_set_str(cX, conf.cX_str, 10); mpf_set_str(cY, conf.cY_str, 10); //rangeG = 10^range mpf_t rangeGx; mpf_init2(rangeGx, precision); mpf_set_d(rangeGx, conf.zoomBase); if(conf.zoomExp < 0) { mpf_pow_ui(rangeGx, rangeGx, -conf.zoomExp); //raise to 10^-range which will be huge mpf_ui_div(rangeGx, 1, rangeGx); //take reciprocol } else { mpf_pow_ui(rangeGx, rangeGx, conf.zoomExp); } mpf_t rangeGy; mpf_init2(rangeGy, precision); //Scale to screen resolution mpf_mul_ui(rangeGy, rangeGx, conf.h); mpf_mul_ui(rangeGx, rangeGx, conf.w); mpf_t xMin, xMax, yMin, yMax; mpf_init2(xMin, precision); mpf_init2(xMax, precision); mpf_init2(yMin, precision); mpf_init2(yMax, precision); mpf_sub(xMin, cX, rangeGx); mpf_add(xMax, cX, rangeGx); mpf_sub(yMin, cY, rangeGy); mpf_add(yMax, cY, rangeGy); for(int i = 0; i < amtToSend; i++) { buf[i] = mandelbrot(curPixel + i, conf.w, conf.h, xMin, xMax, yMin, yMax, conf.zoomExp, conf.maxIter, precision); } mpf_clears(cX, cY, rangeGx, rangeGy, xMin, xMax, yMin, yMax, NULL); MPI_Send(buf, sizeof(Pixel) * amtToSend, MPI_BYTE, 0, 0, MPI_COMM_WORLD); } } free(buf); }