/*********************/ /* Graphics routines */ /*********************/ #include "colors_waves.c" #define CLUSTER_SHIFT 10 /* shift in numbering of open clusters */ int writetiff(char *filename, char *description, int x, int y, int width, int height, int compression) { TIFF *file; GLubyte *image, *p; int i; file = TIFFOpen(filename, "w"); if (file == NULL) { return 1; } image = (GLubyte *) malloc(width * height * sizeof(GLubyte) * 3); /* OpenGL's default 4 byte pack alignment would leave extra bytes at the end of each image row so that each full row contained a number of bytes divisible by 4. Ie, an RGB row with 3 pixels and 8-bit componets would be laid out like "RGBRGBRGBxxx" where the last three "xxx" bytes exist just to pad the row out to 12 bytes (12 is divisible by 4). To make sure the rows are packed as tight as possible (no row padding), set the pack alignment to 1. */ glPixelStorei(GL_PACK_ALIGNMENT, 1); glReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, image); TIFFSetField(file, TIFFTAG_IMAGEWIDTH, (uint32) width); TIFFSetField(file, TIFFTAG_IMAGELENGTH, (uint32) height); TIFFSetField(file, TIFFTAG_BITSPERSAMPLE, 8); TIFFSetField(file, TIFFTAG_COMPRESSION, compression); TIFFSetField(file, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); TIFFSetField(file, TIFFTAG_ORIENTATION, ORIENTATION_BOTLEFT); TIFFSetField(file, TIFFTAG_SAMPLESPERPIXEL, 3); TIFFSetField(file, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(file, TIFFTAG_ROWSPERSTRIP, 1); TIFFSetField(file, TIFFTAG_IMAGEDESCRIPTION, description); p = image; for (i = height - 1; i >= 0; i--) { // if (TIFFWriteScanline(file, p, height - i - 1, 0) < 0) if (TIFFWriteScanline(file, p, i, 0) < 0) { free(image); TIFFClose(file); return 1; } p += width * sizeof(GLubyte) * 3; } TIFFClose(file); return 0; } void init() /* initialisation of window */ { glLineWidth(3); glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); // glOrtho(XMIN, XMAX, YMIN, YMAX , -1.0, 1.0); glOrtho(0.0, NX, 0.0, NY, -1.0, 1.0); } void blank() { if (BLACK) glClearColor(0.0, 0.0, 0.0, 1.0); else glClearColor(1.0, 1.0, 1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); } void write_text_fixedwidth( double x, double y, char *st) { int l, i; l=strlen( st ); // see how many characters are in text string. glRasterPos2d( x, y); // location to start printing text for( i=0; i < l; i++) // loop until i is greater then l { // glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, st[i]); // Print a character on the screen // glutBitmapCharacter(GLUT_BITMAP_8_BY_13, st[i]); // Print a character on the screen glutBitmapCharacter(GLUT_BITMAP_9_BY_15, st[i]); // Print a character on the screen } } void write_text( double x, double y, char *st) { int l,i; l=strlen( st ); // see how many characters are in text string. glRasterPos2d( x, y); // location to start printing text for( i=0; i < l; i++) // loop until i is greater then l { glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, st[i]); // Print a character on the screen // glutBitmapCharacter(GLUT_BITMAP_8_BY_13, st[i]); // Print a character on the screen } } void save_frame_perc() { static int counter = 0; char *name="perc.", n2[100]; char format[6]=".%05i"; counter++; strcpy(n2, name); sprintf(strstr(n2,"."), format, counter); strcat(n2, ".tif"); printf(" saving frame %s \n",n2); writetiff(n2, "Wave equation in a planar domain", 0, 0, WINWIDTH, WINHEIGHT, COMPRESSION_LZW); } /*********************/ /* some basic math */ /*********************/ double ipow(double x, int n) { double y; int i; y = x; for (i=1; i 0.5) return(pstar + factor*(1.0 - pstar)*ipow(time - 0.5, power)); else return(pstar - factor*pstar*ipow(0.5 - time, power)); } int in_plot_box(double x, double y) { int pos[2]; static double xmin, xmax, ymin, ymax; static int first = 1; if (first) { xy_to_ij(XMAX - 1.0, YMAX - 1.0, pos); xmin = (double)pos[0]; ymin = (double)pos[1]; first = 0; } return((x > xmin)&&(y > ymin)); // return((x + 0.5*(double)size > xmin)&&(y + 0.5*(double)size > ymin)); } double size_ratio_color(int clustersize, int ncells) /* color of cell as function of the size of its cluster */ { double ratio, minratio = 1.0e-2, x; ratio = (double)clustersize/(double)ncells; if (ratio > 1.0) ratio = 1.0; else if (ratio < minratio) ratio = minratio; x = log(ratio/minratio)/log(1.0/minratio); return(CLUSTER_HUEMIN*x + CLUSTER_HUEMAX*(1.0 -x)); /* other attempts that seem to bug */ // ratio = log((double)(clustersize+1))/log((double)(ncells+1)); // // ratio = ((double)clustersize)/((double)ncells); // // ratio = sqrt((double)clustersize)/sqrt((double)ncells); // if (ratio > 1.0) ratio = 1.0; // else if (ratio < 0.0) ratio = 0.0; // return(CLUSTER_HUEMAX*ratio + CLUSTER_HUEMIN*(1.0 -ratio)); } void set_cell_color(t_perco cell, int *cluster_sizes, int fade, int max_cluster_size) /* compute color of cell */ { int k, color, csize; double rgb[3], fade_factor = 0.15, hue; if (!cell.open) hsl_to_rgb_palette(HUE_CLOSED, 0.9, 0.5, rgb, COLOR_PALETTE); else { if (!cell.flooded) hsl_to_rgb_palette(HUE_OPEN, 0.9, 0.5, rgb, COLOR_PALETTE); else hsl_to_rgb_palette(HUE_FLOODED, 0.9, 0.5, rgb, COLOR_PALETTE); if ((FIND_ALL_CLUSTERS)&&(COLOR_CLUSTERS_BY_SIZE)) { csize = cluster_sizes[cell.cluster]; hue = size_ratio_color(csize, max_cluster_size); hsl_to_rgb_palette(hue, 0.9, 0.5, rgb, COLOR_PALETTE); } else if ((FIND_ALL_CLUSTERS)&&(cell.cluster > 1)) { color = cell.cluster%N_CLUSTER_COLORS; hue = CLUSTER_HUEMIN + (CLUSTER_HUEMAX - CLUSTER_HUEMIN)*(double)color/(double)N_CLUSTER_COLORS; hsl_to_rgb_palette(hue, 0.9, 0.5, rgb, COLOR_PALETTE); } } if (fade) for (k=0; k<3; k++) rgb[k] = 1.0 - fade_factor + fade_factor*rgb[k]; glColor3f(rgb[0], rgb[1], rgb[2]); } double plot_coord(double x, double xmin, double xmax) { return(xmin + x*(xmax - xmin)); } void draw_size_plot(double plot_cluster_size[NSTEPS], int i, double pcrit) /* draw plot of cluster sizes in terms of p */ { int j; char message[100]; static double xmin, xmax, ymin, ymax, xmid, ymid, dx, dy, plotxmin, plotxmax, plotymin, plotymax; double pos[2], x1, y1, x2, y2, rgb[3], x; static int first = 1; if (first) { xmin = XMAX - 0.95; xmax = XMAX - 0.05; ymin = YMAX - 0.95; ymax = YMAX - 0.05; xmid = 0.5*(xmin + xmax); ymid = 0.5*(ymin + ymax); dx = 0.5*(xmax - xmin); dy = 0.5*(ymax - ymin); plotxmin = xmin + 0.05; plotxmax = xmax - 0.1; plotymin = ymin + 0.07; plotymax = ymax - 0.15; first = 0; } rgb[0] = 1.0; rgb[1] = 1.0; rgb[2] = 1.0; // erase_area_rgb(xmid, ymid, dx, dy, rgb); glColor3f(0.0, 0.0, 0.0); glLineWidth(2); /* axes and labels */ draw_line(plotxmin, plotymin, plotxmax + 0.05, plotymin); draw_line(plotxmin, plotymin, plotxmin, plotymax + 0.1); draw_line(plotxmin - 0.02, plotymax, plotxmin + 0.02, plotymax); x = plot_coord(pcrit, plotxmin, plotxmax); draw_line(x, plotymin, x, plotymax); draw_line(plotxmax, plotymin - 0.02, plotxmax, plotymin + 0.02); xy_to_pos(plotxmax + 0.06, plotymin - 0.03, pos); sprintf(message, "p"); write_text_fixedwidth(pos[0], pos[1], message); xy_to_pos(plotxmax - 0.015, plotymin - 0.06, pos); sprintf(message, "1"); write_text_fixedwidth(pos[0], pos[1], message); xy_to_pos(x - 0.02, plotymin - 0.04, pos); sprintf(message, "pc"); write_text_fixedwidth(pos[0], pos[1], message); xy_to_pos(plotxmin + 0.02, plotymax + 0.05, pos); sprintf(message, "nflooded/nopen"); write_text_fixedwidth(pos[0], pos[1], message); xy_to_pos(plotxmin - 0.05, plotymax - 0.01, pos); sprintf(message, "1"); write_text_fixedwidth(pos[0], pos[1], message); /* plot */ hsl_to_rgb_palette(HUE_GRAPH, 0.9, 0.5, rgb, COLOR_PALETTE); glColor3f(rgb[0], rgb[1], rgb[2]); x1 = plotxmin; y1 = plotymin; for (j=0; j 0) { // if (maxclustersize < maxbins) nbins = maxclustersize; // else nbins = maxbins; histo = (int *)malloc(nbins*sizeof(int)); for (bin = 0; bin < nbins; bin++) histo[bin] = 0; // binwidth = maxclustersize/nbins; // if (binwidth == 0) binwidth = 1; binwidth = maxclustersize/nbins + 1; /* compute histogram */ for (i=CLUSTER_SHIFT; i 0) { bin = (cluster_sizes[i]-1)/binwidth; histo[bin]++; } for (bin=0; bin maxheight) maxheight = histo[bin]; /* draw histogram */ glColor3f(0.0, 0.0, 0.0); glLineWidth(2); x1 = plotxmin; y1 = plotymin; max_x_axis = maxclustersize; if (max_x_axis < HISTO_BINS) max_x_axis = HISTO_BINS; for (bin=0; bin < nbins; bin++) { csize = bin*binwidth + binwidth/2; hue = size_ratio_color(csize, ncells); x2 = plot_coord((double)((bin+1)*binwidth)/(double)(max_x_axis+1), plotxmin, plotxmax); // x2 = plot_coord((double)(bin+1)/(double)nbins, plotxmin, plotxmax); y = log((double)(histo[bin]+1))/log((double)(maxheight+1)); y2 = plot_coord(y, plotymin, plotymax); draw_colored_rectangle(x1, y1, x2, y2, hue); x1 = x2; } draw_line(plotxmin, plotymin, plotxmax + 0.05, plotymin); draw_line(plotxmin, plotymin, plotxmin, plotymax + 0.1); /* graduation of y axis */ x = log((double)(maxheight+1))/log(10.0); for (i=0; i<(int)x + 1; i++) { n = ipowi(10, i); y = log((double)(n+1))/log((double)(maxheight+1)); y1 = plot_coord(y, plotymin, plotymax); xy_to_pos(plotxmin - 0.1, y1, pos); draw_line(plotxmin - 0.02, y1, plotxmin + 0.02, y1); sprintf(message, "%i", n); xy_to_pos(plotxmin - 0.07 - 0.025*(double)i, y1 - 0.01, pos); write_text_fixedwidth(pos[0], pos[1], message); } /* graduation of x axis */ x = log((double)(max_x_axis+1))/log(10.0); n = ipowi(10, (int)x); y = (double)n/10.0; delta = plot_coord((double)n/((double)(max_x_axis+1)), plotxmin, plotxmax) - plotxmin; if (delta > 0.13 + 0.01*x) di = 1; else if (delta > 0.08 + 0.01*x) di = 2; else di = 5; for (i=di; i<10; i+=di) { x1 = plot_coord(y*(double)i*10.0/(double)(max_x_axis+1), plotxmin, plotxmax); if (i*n < max_x_axis*11/10) { sprintf(message, "%i", i*n); xy_to_pos(x1 + 0.005 - 0.012*x, plotymin - 0.07, pos); write_text_fixedwidth(pos[0], pos[1], message); } } delta = plot_coord((double)n/(10.0*(double)(max_x_axis+1)), plotxmin, plotxmax) - plotxmin; for (i=0; i<100; i++) if (i*n < 11*max_x_axis) { y = (double)(i*n)/10.0; x1 = plot_coord(y/(double)(max_x_axis+1), plotxmin, plotxmax); xy_to_pos(x1, plotymin , pos); if (i%10 == 0) draw_line(x1, plotymin - 0.02, x1, plotymin + 0.02); else if (delta > 0.02) draw_line(x1, plotymin - 0.01, x1, plotymin + 0.01); } /* for debugging */ if (DEBUG) for (bin=0; bin < nbins; bin++) printf("Bin %i = %i\n", bin, histo[bin]); free(histo); } } void draw_cell(int c, int nx, int ny, int size) /* draw a single cell, for debugging puposes */ { int i, j, ishift, k, group; double rgb[3], x, y, alpha, r, fade = 0, dsize; static double h; static int first = 1; dsize = (double)size; group = cell_to_ij(c, &i, &j, nx, ny); switch (graphical_rep(LATTICE)) { case (PLOT_SQUARES): { glBegin(GL_QUADS); glVertex2i(i*size, j*size); glVertex2i((i+1)*size, j*size); glVertex2i((i+1)*size, (j+1)*size); glVertex2i(i*size, (j+1)*size); glEnd (); break; } case (PLOT_SQUARE_BONDS): { glLineWidth(5); glBegin(GL_LINES); /* horizontal segments */ if (group == 0) { glVertex2i(i*size, j*size); glVertex2i((i+1)*size, j*size); } /* vertical segments */ else { glVertex2i(i*size, j*size); glVertex2i(i*size, (j+1)*size); } glEnd (); break; } case (PLOT_HEX): { if (first) { h = 0.5*sqrt(3.0); first = 0; } r = (double)size*0.5/h; x = ((double)i + 0.75)*dsize; if (j%2 == 1) x += 0.5*dsize; y = h*dsize*((double)j + 1.0); glBegin(GL_TRIANGLE_FAN); glVertex2d(x, y); for (k=0; k<7; k++) { alpha = (1.0 + 2.0*(double)k)*PI/6.0; glVertex2d(x + r*cos(alpha), y + r*sin(alpha)); } glEnd(); break; } case (PLOT_HEX_BONDS): { if (first) { h = 0.5*sqrt(3.0); first = 0; } r = (double)size*0.5/h; x = ((double)i + 0.75)*dsize; if (j%2 == 1) x -= 0.5*dsize; y = h*dsize*((double)j + 1.0); glBegin(GL_LINES); switch (group){ case (0): /* vertical bonds */ { glVertex2d(x-0.5*dsize, y+0.5*r); glVertex2d(x-0.5*dsize, y-0.5*r); break; } case (1): /* NE-SW bonds */ { glVertex2d(x, y-r); glVertex2d(x+0.5*dsize, y-0.5*r); break; } case (2): /* NW-SE bonds */ { glVertex2d(x-0.5*dsize, y-0.5*r); glVertex2d(x, y-r); break; } } glEnd(); break; } case (PLOT_TRIANGLE): { if (first) { h = 0.5*sqrt(3.0); first = 0; } r = (double)size*0.5/h; x = 0.5*((double)i + 1.25)*dsize; y = h*dsize*((double)j); printf("Drawing cell %i = (%i, %i) at (%.0f, %.0f)\n", c, i, j, x, y); glBegin(GL_TRIANGLES); if ((i+j)%2 == 1) { glVertex2d(x-0.5*dsize, y); glVertex2d(x+0.5*dsize, y); glVertex2d(x, y+h*dsize); } else { glVertex2d(x-0.5*dsize, y+h*dsize); glVertex2d(x+0.5*dsize, y+h*dsize); glVertex2d(x, y); } glEnd(); break; } } } void test_neighbours(int start, t_perco *cell, int nx, int ny, int size, int ncells) /* for debugging puposes */ { int i, k; for (i=start; i 1280) erase_area_rgb(xrightbox, y + 0.025, 0.15, 0.05, rgb); else erase_area_rgb(xrightbox, y + 0.025, 0.22, 0.05, rgb); } glColor3f(0.0, 0.0, 0.0); if (NX > 1280) xy_to_pos(xrighttext + 0.35, y, pos); else xy_to_pos(xrighttext + 0.3, y, pos); sprintf(message, "p = %.4f", p); write_text(pos[0], pos[1], message); } void print_nclusters(int nclusters) { char message[100]; double y = YMAX - 0.25, pos[2], rgb[3] = {1.0, 1.0, 1.0}; static double xleftbox, xlefttext, xrightbox, xrighttext; static int first = 1; if (first) { xleftbox = XMIN + 0.2; xlefttext = xleftbox - 0.45; xrightbox = XMAX - 0.31; xrighttext = xrightbox - 0.48; first = 0; } if (!PLOT_CLUSTER_SIZE) { if (NX > 1280) erase_area_rgb(xrightbox, y + 0.025, 0.18, 0.05, rgb); else erase_area_rgb(xrightbox, y + 0.025, 0.25, 0.05, rgb); } glColor3f(0.0, 0.0, 0.0); if (NX > 1280) xy_to_pos(xrighttext + 0.35, y, pos); else xy_to_pos(xrighttext + 0.3, y, pos); if (nclusters == 1) sprintf(message, "%i cluster", nclusters); else sprintf(message, "%i clusters", nclusters); write_text_fixedwidth(pos[0], pos[1], message); } void print_largest_cluster_size(int max_cluster_size) { char message[100]; double y = YMAX - 0.25, pos[2], rgb[3] = {1.0, 1.0, 1.0}; static double xleftbox, xlefttext, xrightbox, xrighttext; static int first = 1; if (first) { xleftbox = XMIN + 0.2; xlefttext = xleftbox - 0.45; xrightbox = XMAX - 0.41; xrighttext = xrightbox - 0.48; first = 0; } if (!PLOT_CLUSTER_SIZE) { if (NX > 1280) erase_area_rgb(xrightbox, y + 0.025, 0.18, 0.05, rgb); else erase_area_rgb(xrightbox, y + 0.025, 0.25, 0.05, rgb); } glColor3f(0.0, 0.0, 0.0); if (NX > 1280) xy_to_pos(xrighttext + 0.35, y, pos); else xy_to_pos(xrighttext + 0.3, y, pos); sprintf(message, "max size %i", max_cluster_size); write_text_fixedwidth(pos[0], pos[1], message); } /*********************/ /* animation part */ /*********************/ int cell_number(int nx, int ny) /* total number of cells in graph */ { switch (LATTICE) { case (BC_SQUARE_DIRICHLET): return(nx*ny); case (BC_SQUARE_PERIODIC): return(nx*ny); case (BC_SQUARE_BOND_DIRICHLET): return(2*nx*ny + nx + ny); case (BC_HEX_SITE_DIRICHLET): return((int)((double)(nx*ny)*2.0/sqrt(3.0))); /* hex lattice requires more vertical space! */ case (BC_HEX_BOND_DIRICHLET): return(3*(int)((double)((nx+2)*(ny+2))*2.0/sqrt(3.0))); /* hex lattice requires more vertical space! */ case (BC_TRIANGLE_SITE_DIRICHLET): return((int)((double)(2*nx*ny)*2.0/sqrt(3.0))); /* triangle lattice requires more vertical space! */ } } void compute_nxny(int size, int *nx, int *ny) /* compute the number of rows and columns depending on lattice */ { switch (LATTICE) { case (BC_HEX_SITE_DIRICHLET): { *nx = NX/size - 1; *ny = (int)((double)NY*2.0/((double)size*sqrt(3.0))); break; } case (BC_HEX_BOND_DIRICHLET): { *nx = NX/size + 1; *ny = (int)((double)NY*2.0/((double)size*sqrt(3.0))) + 1; break; } case (BC_TRIANGLE_SITE_DIRICHLET): { *nx = NX/size - 1; *ny = (int)((double)NY*2.0/((double)size*sqrt(3.0))) + 1; break; } default: { *nx = NX/size; *ny = NY/size; } } } int init_cell_lattice(t_perco *cell, int nx, int ny) /* initialize the graph of connected cells - returns the number of cells */ { int i, j, iplus, iminus, ishift, n; printf("Initializing cell lattice ..."); switch (LATTICE) { case (BC_SQUARE_DIRICHLET): { /* neighbours in the bulk */ #pragma omp parallel for private(i,j) for (i=1; iopen); if (!pstack[position]->open) return(-1); pstack[position]->cluster = cluster; for (k=0; knneighb; k++) { n = pstack[position]->nghb[k]; if ((cell[n].open)&&(cell[n].cluster != cluster)) { cell[n].flooded = 1; cell[n].tested = 1; cell[n].cluster = cluster; cell[n].active = 1; nopen++; if (*stacksize < ncells) { (*stacksize)++; pstack[*stacksize-1] = &cell[n]; } } } if (nopen == 0) { pstack[position]->active = 0; return(-1); } else return(nopen); } int find_percolation_cluster(t_perco *cell, int ncells, t_perco* *pstack, int nstack) /* new version of cluster search algorithm, using stacks; returns number of flooded cells */ { int position = 0, i, stacksize = nstack, nactive = nstack; while (nactive > 0) { /* find an active cell in stack */ while (!pstack[position]->active) position++; if (position == stacksize) position = 0; nactive += find_open_cells(cell, ncells, position, pstack, &stacksize, 1); } printf("Stack size %i\n", stacksize); return(stacksize); } int find_all_clusters(t_perco *cell, int ncells, int reset, int *max_cluster_label) /* find all clusters of open cells; returns number of clusters */ { int nclusters = 0, i, j, nactive, stacksize, position, newcluster = 1, maxlabel = 0; t_perco **cstack; static int cluster; cstack = (t_perco* *)malloc(ncells*sizeof(struct t_perco *)); if (reset) cluster = CLUSTER_SHIFT; else cluster = (*max_cluster_label) + CLUSTER_SHIFT; /* give higher labels than before to new clusters */ for (i=0; i= CLUSTER_SHIFT) newcluster = cell[i].previous_cluster; else { newcluster = cluster; cluster++; } cell[i].cluster = newcluster; cell[i].active = 1; cell[i].tested = 1; while (nactive > 0) { /* find an active cell in stack */ while (!cstack[position]->active) position++; if (position == stacksize) position = 0; nactive += find_open_cells(cell, ncells, position, cstack, &stacksize, newcluster); } // printf("Found cluster %i with %i active cells\n", cluster, stacksize); nclusters++; } free(cstack); /* determine maximal cluster label */ // #pragma omp parallel for private(i) for (i=0; i maxlabel)) maxlabel = cell[i].cluster; printf("Cluster = %i, maxlabel = %i\n", cluster, maxlabel); *max_cluster_label = maxlabel; return(nclusters); } void print_cluster_sizes(t_perco *cell, int ncells, int *cluster_sizes) /* for debugging purposes */ { int j; for (j=0; j ncells) maxclusterlabel = ncells; /* determine label of larges cluster */ for (i=0; i maxlabel) maxlabel = cell[i].cluster; *maxclusterlabel = maxlabel + 1; #pragma omp parallel for private(i) for (i=0; i<*maxclusterlabel; i++) cluster_sizes[i] = 0; for (i=0; i max) max = cluster_sizes[i]; // for (i=0; i