double courant2; /* Courant parameter squared */ double dx2; /* spatial step size squared */ double intstep; /* integration step */ double intstep1; /* integration step used in absorbing boundary conditions */ double viscosity; /* viscosity (parameter in front of Laplacian) */ double rpslzb; /* second parameter in Rock-Paper-Scissors-Lizard-Spock equation */ double gaussian() /* returns standard normal random variable, using Box-Mueller algorithm */ { static double V1, V2, S; static int phase = 0; double X; if (phase == 0) { do { double U1 = (double)rand() / RAND_MAX; double U2 = (double)rand() / RAND_MAX; V1 = 2 * U1 - 1; V2 = 2 * U2 - 1; S = V1 * V1 + V2 * V2; } while(S >= 1 || S == 0); X = V1 * sqrt(-2 * log(S) / S); } else X = V2 * sqrt(-2 * log(S) / S); phase = 1 - phase; return X; } void init_random(double mean, double amplitude, double *phi[NFIELDS], short int xy_in[NX*NY]) /* initialise field with gaussian at position (x,y) */ { int i, j, k, in; double xy[2], dist2, module, phase, scale2; printf("Initialising xy_in\n"); #pragma omp parallel for private(i,j) for (i=0; i= 2) phi[i][j] = T_IN*pow(0.75, (double)(in-2)); // else if (in >= 2) phi[i][j] = T_IN*pow(1.0 - 0.5*(double)(in-2), (double)(in-2)); // else if (in >= 2) phi[i][j] = T_IN*(1.0 - (double)(in-2)/((double)MDEPTH))*(1.0 - (double)(in-2)/((double)MDEPTH)); else phi[i][j] = T_OUT; } } void init_coherent_state(double x, double y, double px, double py, double scalex, double *phi[NFIELDS], short int xy_in[NX*NY]) /* initialise field with coherent state of position (x,y) and momentum (px, py) */ /* phi[0] is real part, phi[1] is imaginary part */ { int i, j; double xy[2], dist2, module, phase, scale2; scale2 = scalex*scalex; for (i=0; i= DPI) return (angle - DPI); else return(angle); } double unwrap_angle(double angle1, double angle2) { if (angle2 - angle1 < -PI) return(angle2 + DPI); else if (angle2 - angle1 >= PI) return (angle2 - DPI); else return(angle2); } void compute_theta(double *phi[NFIELDS], short int xy_in[NX*NY], t_rde rde[NX*NY]) /* compute angle for rock-paper-scissors equation */ { int i, j; double u, v, w, rho, xc, yc, angle; #pragma omp parallel for private(i,j,u, v, w, rho, xc, yc, angle) for (i=0; i= DPI) angle -= DPI; rde[i*NY+j].theta = angle; } else rde[i*NY+j].theta = 0.0; } double colors_rpslz(int type) { switch (type) { case (0): return(0.0); case (1): return(60.0); case (2): return(120.0); case (3): return(200.0); case (4): return(270.0); } } void compute_theta_rpslz(double *phi[NFIELDS], short int xy_in[NX*NY], t_rde rde[NX*NY], int cplot) /* compute angle for rock-paper -scissors-lizard-Spock equation */ { int i, j, k, kmax; double rho, xc, yc, angle, max; static double sa[5], ca[5], shift; static int first = 1; if (first) { // shift = 0.0; for (i = 0; i < 5; i++) { ca[i] = cos(colors_rpslz(i)*DPI/360.0); sa[i] = sin(colors_rpslz(i)*DPI/360.0); // ca[i] = cos(shift + 0.2*DPI*(double)i); // sa[i] = sin(shift + 0.2*DPI*(double)i); } first = 0; } switch (cplot) { case (Z_MAXTYPE_RPSLZ): { #pragma omp parallel for private(i,j,max,kmax) for (i=0; i max) { max = phi[k][i*NY+j]; kmax = k; } } angle = colors_rpslz(kmax); rde[i*NY+j].theta = angle; } else rde[i*NY+j].theta = 0.0; } break; } // case (Z_THETA_RPSLZ): default: { #pragma omp parallel for private(i,j,rho,xc,yc,angle) for (i=0; i= DPI) angle -= DPI; rde[i*NY+j].theta = angle; } else rde[i*NY+j].theta = 0.0; } break; } } } void compute_gradient_rde(double phi[NX*NY], t_rde rde[NX*NY]) /* compute the gradient of the field */ { int i, j, iplus, iminus, jplus, jminus; double deltaphi; double dx = (XMAX-XMIN)/((double)NX); dx = (XMAX-XMIN)/((double)NX); #pragma omp parallel for private(i,j,iplus,iminus,jplus,jminus,deltaphi) for (i=0; i PI) deltaphi -= DPI; if (vabs(deltaphi) < 1.0e9) rde[i*NY+j].nablax = (deltaphi)/dx; else rde[i*NY+j].nablax = 0.0; deltaphi = phi[i*NY+jplus] - phi[i*NY+jminus]; if (deltaphi < -PI) deltaphi += DPI; if (deltaphi > PI) deltaphi -= DPI; if (vabs(deltaphi) < 1.0e9) rde[i*NY+j].nablay = (deltaphi)/dx; else rde[i*NY+j].nablay = 0.0; /* TO DO: improve this computation */ rde[i*NY+j].field_norm = module2(rde[i*NY+j].nablax,rde[i*NY+j].nablay); rde[i*NY+j].field_arg = argument(rde[i*NY+j].nablax,rde[i*NY+j].nablay); } } void compute_gradient_theta(t_rde rde[NX*NY]) /* compute the gradient of the theta field */ { int i, j, iplus, iminus, jplus, jminus; double deltaphi; double dx = (XMAX-XMIN)/((double)NX); dx = (XMAX-XMIN)/((double)NX); #pragma omp parallel for private(i,j,iplus,iminus,jplus,jminus,deltaphi) for (i=0; i PI) deltaphi -= DPI; if (vabs(deltaphi) < 1.0e9) rde[i*NY+j].nablax = (deltaphi)/dx; else rde[i*NY+j].nablax = 0.0; deltaphi = rde[i*NY+jplus].theta - rde[i*NY+jminus].theta; if (deltaphi < -PI) deltaphi += DPI; if (deltaphi > PI) deltaphi -= DPI; if (vabs(deltaphi) < 1.0e9) rde[i*NY+j].nablay = (deltaphi)/dx; else rde[i*NY+j].nablay = 0.0; } } void compute_curl(t_rde rde[NX*NY]) /* compute the curl of the field */ { int i, j, iplus, iminus, jplus, jminus; double delta; double dx = (XMAX-XMIN)/((double)NX); dx = (XMAX-XMIN)/((double)NX); #pragma omp parallel for private(i,j,iplus,iminus,jplus,jminus,delta) for (i=0; i= DPI) angle -= DPI; rde[i*NY+j].field_arg = angle; } } void compute_field_module(double *phi[NFIELDS], t_rde rde[NX*NY], double factor) /* compute the norm squared of first two fields */ { int i, j; #pragma omp parallel for private(i,j) for (i=0; i= DPI) arg -= DPI; rde[i*NY+j].field_arg = arg; } } // void compute_field_norm(double phi_x[NX*NY], double phi_y[NX*NY], double phi_norm[NX*NY], double factor) // /* compute the norm of (phi_x, phi_y) */ // { // int i, j; // // #pragma omp parallel for private(i,j) // for (i=0; i= DPI) angle -= DPI; // phi_arg[i*NY+j] = 360.0*angle/DPI; // // phi_arg[i*NY+j] = 180.0*angle/DPI; // } // } void compute_laplacian(double phi_in[NX*NY], double phi_out[NX*NY], short int xy_in[NX*NY]) /* computes the Laplacian of phi_in and stores it in phi_out */ { int i, j, iplus, iminus, jplus, jminus; #pragma omp parallel for private(i,j,iplus,iminus,jplus,jminus) for (i=1; i NX-1) ij[0] = NX-1; if (ij[1] < 0) ij[1] = 0; if (ij[1] > NY-1) ij[1] = NY-1; nabx = nablax[ij[0]][ij[1]]; naby = nablay[ij[0]][ij[1]]; norm2 = nabx*nabx + naby*naby; if (norm2 > 1.0e-14) { /* avoid too large step size */ if (norm2 < 1.0e-9) norm2 = 1.0e-9; norm = sqrt(norm2); x1 = x1 + delta*nabx/norm; y1 = y1 + delta*naby/norm; } else cont = 0; if (!xy_in[ij[0]*NY + ij[1]]) cont = 0; /* stop if the boundary is hit */ // if (xy_in[ij[0]][ij[1]] != 1) cont = 0; // printf("x1 = %.3lg \t y1 = %.3lg \n", x1, y1); xy_to_pos(x1, y1, pos); glVertex2d(pos[0], pos[1]); i++; } glEnd(); } void compute_field_color_rde(double value, int cplot, int palette, double rgb[3]) /* compute the color depending on the field value and color palette */ { switch (cplot) { case (Z_AMPLITUDE): { color_scheme_palette(COLOR_SCHEME, palette, value, 1.0, 0, rgb); break; } case (Z_RGB): { /* TO DO */ break; } case (Z_POLAR): { // hsl_to_rgb_palette(360.0*value/DPI, 0.9, 0.5, rgb, palette); color_scheme_palette(C_ONEDIM_LINEAR, palette, value/DPI, 1.0, 1, rgb); break; } case (Z_NORM_GRADIENT): { color_scheme_palette(COLOR_SCHEME, palette, value, 1.0, 0, rgb); break; } case (Z_ANGLE_GRADIENT): { color_scheme_palette(C_ONEDIM_LINEAR, palette, value/DPI, 1.0, 1, rgb); break; } case (Z_NORM_GRADIENTX): { hsl_to_rgb_palette(360.0*value/DPI, 0.9, 0.5, rgb, palette); break; } case (Z_ANGLE_GRADIENTX): { color_scheme_palette(C_ONEDIM_LINEAR, palette, value/DPI, 1.0, 1, rgb); break; } case (Z_NORM_GRADIENT_INTENSITY): { hsl_to_rgb_palette(360.0*value/DPI, 0.9, 0.5, rgb, palette); break; } case (Z_VORTICITY): { hsl_to_rgb_palette(180.0*(1.0 - color_amplitude(value, 1.0, 0)), 0.9, 0.5, rgb, palette); break; } case (Z_MAXTYPE_RPSLZ): { hsl_to_rgb_palette(value, 0.9, 0.5, rgb, palette); break; } case (Z_THETA_RPSLZ): { color_scheme_palette(C_ONEDIM_LINEAR, palette, value/DPI, 1.0, 1, rgb); break; } case (Z_NORM_GRADIENT_RPSLZ): { color_scheme_palette(COLOR_SCHEME, palette, value, 1.0, 0, rgb); break; } case (Z_MODULE): { color_scheme_asym_palette(COLOR_SCHEME, palette, VSCALE_AMPLITUDE*value, 1.0, 0, rgb); break; } case (Z_ARGUMENT): { color_scheme_palette(C_ONEDIM_LINEAR, palette, value/DPI, 1.0, 1, rgb); break; } } } double compute_interpolated_colors_rde(int i, int j, t_rde rde[NX*NY], double palette, int cplot, double rgb_e[3], double rgb_w[3], double rgb_n[3], double rgb_s[3], int fade, double fade_value, int movie) { int k; double cw, ce, cn, cs, c_sw, c_se, c_nw, c_ne, c_mid, ca, z_mid; double *z_sw, *z_se, *z_nw, *z_ne, lum; z_sw = rde[i*NY+j].p_zfield[movie]; z_se = rde[(i+1)*NY+j].p_zfield[movie]; z_nw = rde[i*NY+j+1].p_zfield[movie]; z_ne = rde[(i+1)*NY+j+1].p_zfield[movie]; z_mid = 0.25*(*z_sw + *z_se + *z_nw + *z_ne); c_sw = *rde[i*NY+j].p_cfield[movie]; c_se = *rde[(i+1)*NY+j].p_cfield[movie]; c_nw = *rde[i*NY+j+1].p_cfield[movie]; c_ne = *rde[(i+1)*NY+j+1].p_cfield[movie]; if (COMPUTE_WRAP_ANGLE) { c_se = unwrap_angle(c_sw,c_se); c_nw = unwrap_angle(c_sw,c_nw); c_ne = unwrap_angle(c_sw,c_ne); } c_mid = 0.25*(c_sw + c_se + c_nw + c_ne); cw = (c_sw + c_nw + c_mid)/3.0; ce = (c_se + c_ne + c_mid)/3.0; cs = (c_sw + c_se + c_mid)/3.0; cn = (c_nw + c_ne + c_mid)/3.0; if (COMPUTE_WRAP_ANGLE) { cw = wrap_angle(cw); ce = wrap_angle(ce); cs = wrap_angle(cs); cn = wrap_angle(cn); } compute_field_color_rde(ce, cplot, palette, rgb_e); compute_field_color_rde(cw, cplot, palette, rgb_w); compute_field_color_rde(cn, cplot, palette, rgb_n); compute_field_color_rde(cs, cplot, palette, rgb_s); if (cplot == Z_ARGUMENT) { lum = tanh(SLOPE_SCHROD_LUM*rde[i*NY+j].field_norm); for (k=0; k<3; k++) { rgb_e[k] *= lum; rgb_w[k] *= lum; rgb_n[k] *= lum; rgb_s[k] *= lum; } } if (SHADE_3D) { ca = rde[i*NY+j].cos_angle; ca = (ca + 1.0)*0.4 + 0.2; for (k=0; k<3; k++) { rgb_e[k] *= ca; rgb_w[k] *= ca; rgb_n[k] *= ca; rgb_s[k] *= ca; } } if (fade) for (k=0; k<3; k++) { rgb_e[k] *= fade_value; rgb_w[k] *= fade_value; rgb_n[k] *= fade_value; rgb_s[k] *= fade_value; } return(z_mid); } void compute_rde_fields(double *phi[NFIELDS], short int xy_in[NX*NY], int zplot, int cplot, t_rde rde[NX*NY]) /* compute the necessary auxiliary fields */ { int i, j; switch (RDE_EQUATION) { case (E_RPS): { if ((COMPUTE_THETA)||(COMPUTE_THETAZ)) compute_theta(phi, xy_in, rde); if ((zplot == Z_NORM_GRADIENT)||(cplot == Z_NORM_GRADIENT)) { compute_gradient_theta(rde); // compute_gradient_polar(rde, 1.0); compute_gradient_polar(rde, 0.003); } if ((zplot == Z_NORM_GRADIENTX)||(cplot == Z_NORM_GRADIENTX)||(zplot == Z_ANGLE_GRADIENTX)||(cplot == Z_ANGLE_GRADIENTX)) { compute_gradient_rde(phi[0], rde); compute_gradient_polar(rde, 0.03); } if ((zplot == Z_VORTICITY)||(cplot == Z_VORTICITY)) { compute_gradient_theta(rde); compute_curl(rde); } break; } case (E_RPSLZ): { compute_theta_rpslz(phi, xy_in, rde, cplot); if ((zplot == Z_NORM_GRADIENT_RPSLZ)||(cplot == Z_NORM_GRADIENT_RPSLZ)) { compute_gradient_theta(rde); compute_gradient_polar(rde, 0.005); } break; } case (E_SCHRODINGER): { compute_field_module(phi, rde, 1.0); if ((zplot == Z_ARGUMENT)||(cplot == Z_ARGUMENT)) { compute_field_argument(phi, rde); } break; } default : break; } } void init_zfield_rde(double *phi[NFIELDS], short int xy_in[NX*NY], int zplot, t_rde rde[NX*NY], int movie) /* compute the necessary fields for the z coordinate */ { int i, j; switch(zplot) { case (Z_AMPLITUDE): { #pragma omp parallel for private(i,j) for (i=0; i 0) { z_mid = compute_interpolated_colors_rde(i, j, rde, palette, cplot, rgb_e, rgb_w, rgb_n, rgb_s, fade, fade_value, movie); ij_to_xy(i, j, xy_sw); ij_to_xy(i+1, j, xy_se); ij_to_xy(i, j+1, xy_nw); ij_to_xy(i+1, j+1, xy_ne); for (k=0; k<2; k++) xy_mid[k] = 0.25*(xy_sw[k] + xy_se[k] + xy_nw[k] + xy_ne[k]); if (AMPLITUDE_HIGH_RES == 1) { glBegin(GL_TRIANGLE_FAN); glColor3f(rgb_w[0], rgb_w[1], rgb_w[2]); draw_vertex_xyz(xy_mid, z_mid); draw_vertex_xyz(xy_nw, *rde[i*NY+j+1].p_zfield[movie]); draw_vertex_xyz(xy_sw, *rde[i*NY+j].p_zfield[movie]); glColor3f(rgb_s[0], rgb_s[1], rgb_s[2]); draw_vertex_xyz(xy_se, *rde[(i+1)*NY+j].p_zfield[movie]); glColor3f(rgb_e[0], rgb_e[1], rgb_e[2]); draw_vertex_xyz(xy_ne, *rde[(i+1)*NY+j+1].p_zfield[movie]); glColor3f(rgb_n[0], rgb_n[1], rgb_n[2]); draw_vertex_xyz(xy_nw, *rde[i*NY+j+1].p_zfield[movie]); glEnd (); } } else { glColor3f(rde[i*NY+j].rgb[0], rde[i*NY+j].rgb[1], rde[i*NY+j].rgb[2]); glBegin(GL_TRIANGLE_FAN); ij_to_xy(i, j, xy); draw_vertex_xyz(xy, *rde[i*NY+j].p_zfield[movie]); ij_to_xy(i+1, j, xy); draw_vertex_xyz(xy, *rde[(i+1)*NY+j].p_zfield[movie]); ij_to_xy(i+1, j+1, xy); draw_vertex_xyz(xy, *rde[(i+1)*NY+j+1].p_zfield[movie]); ij_to_xy(i, j+1, xy); draw_vertex_xyz(xy, *rde[i*NY+j+1].p_zfield[movie]); glEnd (); } } } if (DRAW_BILLIARD_FRONT) draw_billiard_3d_front(fade, fade_value); } void draw_wave_rde(int movie, double *phi[NFIELDS], short int xy_in[NX*NY], t_rde rde[NX*NY], int zplot, int cplot, int palette, int fade, double fade_value, int refresh) { int i, j, k, l, draw = 1; double xy[2], xy_screen[2], rgb[3], pos[2], ca, rgb_e[3], rgb_w[3], rgb_n[3], rgb_s[3]; double z_sw, z_se, z_nw, z_ne, z_mid, zw, ze, zn, zs, min = 1000.0, max = 0.0; double xy_sw[2], xy_se[2], xy_nw[2], xy_ne[2], xy_mid[2]; double energy; if (refresh) { // printf("Computing fields\n"); compute_rde_fields(phi, xy_in, zplot, cplot, rde); // printf("Computed fields\n"); if ((PLOT_3D)&&(SHADE_3D)) compute_light_angle_rde(xy_in, rde, movie); } compute_cfield_rde(xy_in, cplot, palette, rde, fade, fade_value, movie); if (PLOT_3D) draw_wave_3d_rde(movie, phi, xy_in, rde, zplot, cplot, palette, fade, fade_value); else draw_wave_2d_rde(xy_in, rde); }